<commit_before>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) 2012 FFLAS-FFPACK group.
 *
 * Extirpé form a m4 macro by BB <bboyer@imag.fr>.
 *
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *
 */

//#define LinBoxSrcOnly
#define DOUBLE_TO_FLOAT_CROSSOVER 0

#include <iostream>
#include <fstream>
#include "fflas-ffpack/config.h"
#include "fflas-ffpack/config-blas.h"
#include "fflas-ffpack/fflas-ffpack-config.h"
#include "fflas-ffpack/utils/timer.h"
#include "givaro/modular.h"
#include "givaro/modular-balanced.h"
#include "fflas-ffpack/fflas/fflas.h"

#ifndef FLTTYPE
#define FLTTYPE Givaro::Modular<double>
#endif
template<class Field>
bool balanced(const Field & )
{
	return false;
}

template <class T>
bool balanced(const Givaro::ModularBalanced<T>&)
{
	return true;
}

#ifdef __GIVARO_USE_OPENMP
typedef Givaro::OMPTimer TTimer;
#else
typedef Givaro::Timer TTimer;
#endif

#define MFLOPS (2.0*iter/chrono.realtime()*(double)n/100.0*(double)n/100.0*(double)n/100.0)

#ifdef __FFLASFFPACK_HAVE_CXX11
#include <ctime>
#endif

//using namespace LinBox;
int main () {
	using namespace std;

	typedef FLTTYPE Field ;
	Field F(17);
	typedef Field::Element Element ;
	size_t n=768, nmax=5000, prec=512, nbest=0, count=0;
    TTimer chrono;
	bool bound=false;
	Field::RandIter G(F);

	Element *A,*B,*C;
	A = FFLAS::fflas_new<Element>(nmax*nmax);
	B = FFLAS::fflas_new<Element>(nmax*nmax);
	C = FFLAS::fflas_new<Element>(nmax*nmax);
	for (size_t i=0; i<nmax*nmax;++i)
		G.random(A[i]);

	for (size_t i=0; i<nmax*nmax;++i)
		G.random(B[i]);

	for (size_t i=0; i<nmax*nmax;++i)
		G.random(C[i]);

	std::ofstream outlog;
	outlog.open("optim.log", std::ofstream::out | std::ofstream::app);
#ifdef __FFLASFFPACK_HAVE_CXX11
    std::time_t result = std::time(NULL);
    outlog << std::endl <<
        "---------------------------------------------------------------------"
           << std::endl << std::asctime(std::localtime(&result));
#endif
	outlog << std::endl
		<< "Threshold for finite field Strassen-Winograd matrix multiplication" ;
	F.write(outlog << "(using ") << ')' << std::endl;
	do {
	double basetime, time;
		FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Winograd> ClassicH(F,0, FFLAS::ParSeqHelper::Sequential());
		FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Winograd> WinogradH(F,1, FFLAS::ParSeqHelper::Sequential());

		int iter=3;
		    //warm up computation
		FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
				n, n, n, F.mOne, A, n, B, n, F.one, C, n, ClassicH);
		chrono.start();
		for (int i=0;i<iter;i++)
			FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans, n, n, n, F.mOne, A, n, B, n, F.one, C, n, ClassicH);
		chrono.stop();
		std::cout << std::endl
			<< "fgemm " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS << " Mffops"
			<< std::endl;
		outlog << std::endl
			<< "fgemm " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS << " Mffops"
			<< std::endl;
		basetime= chrono.realtime();
		    //warm up
		FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
			     n, n, n, F.mOne, A, n, B, n, F.one, C, n, WinogradH);
		chrono.clear();
		chrono.start();
		for (int i=0; i<iter; i++)
			FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
				     n, n, n, F.mOne, A, n, B,n, F.one, C, n, WinogradH);
		chrono.stop();
		std::cout << "1Wino " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS  << " Mffops"
			<< std::endl;
		outlog << "1Wino " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS  << " Mffops"
			<< std::endl;
		time= chrono.realtime();

		if (basetime > time ){
			count++;
			if (count > 1){
				nbest=n;
				bound=true;
				prec=prec>>1;
				n-=prec;
			}
		}
		else{
			count=0;
			if (bound)
				prec=prec>>1;
			n+=prec;
		}
	} while ((prec > 64 ) && (n < nmax));

	std::ofstream out("WinoThreshold");
	if (nbest != 0 ) {
	if (typeid(Element).name() == typeid(double).name()) {
		if ( balanced(F) ) {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_BAL"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_BAL" << ' ' <<  nbest << endl;
		}
		else {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD" << ' ' <<  nbest << endl;
		}
		out << "#endif"                               << endl  << endl;
	}

	if (typeid(Element).name() == typeid(float).name()) {
		if ( balanced(F) ) {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_BAL_FLT"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_BAL_FLT" << ' ' << nbest << endl;
		}
		else {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_FLT"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_FLT" << ' ' << nbest << endl;
		}
		out << "#endif"                               << endl  << endl;
	}
	}
	out.close();

	outlog << "defined __FFLASFFPACK_WINOTHRESHOLD to " << nbest << "" << std::endl;
	outlog.close();

	FFLAS::fflas_delete( A);
	FFLAS::fflas_delete( C);

	return 0;
}
<commit_msg>givaro <commit_after>/* -*- mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
// vim:sts=8:sw=8:ts=8:noet:sr:cino=>s,f0,{0,g0,(0,\:0,t0,+0,=s

/*
 * Copyright (C) 2012 FFLAS-FFPACK group.
 *
 * Extirpé form a m4 macro by BB <bboyer@imag.fr>.
 *
 *
 * ========LICENCE========
 * This file is part of the library FFLAS-FFPACK.
 *
 * FFLAS-FFPACK 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 *
 */

//#define LinBoxSrcOnly
#define DOUBLE_TO_FLOAT_CROSSOVER 0

#include <iostream>
#include <fstream>
#include <givaro/modular.h>
#include <givaro/modular-balanced.h>
#include "fflas-ffpack/config.h"
#include "fflas-ffpack/config-blas.h"
#include "fflas-ffpack/fflas-ffpack-config.h"
#include "fflas-ffpack/utils/timer.h"
#include "fflas-ffpack/fflas/fflas.h"

#ifndef FLTTYPE
#define FLTTYPE Givaro::Modular<double>
#endif

template<class Field>
bool balanced(const Field & )
{
	return false;
}

template <class T>
bool balanced(const Givaro::ModularBalanced<T>&)
{
	return true;
}

#ifdef __GIVARO_USE_OPENMP
typedef Givaro::OMPTimer TTimer;
#else
typedef Givaro::Timer TTimer;
#endif

#define MFLOPS (2.0*iter/chrono.realtime()*(double)n/100.0*(double)n/100.0*(double)n/100.0)

#ifdef __FFLASFFPACK_HAVE_CXX11
#include <ctime>
#endif

//using namespace LinBox;
int main () {
	using namespace std;

	typedef FLTTYPE Field ;
	Field F(17);
	typedef Field::Element Element ;
	size_t n=768, nmax=5000, prec=512, nbest=0, count=0;
    TTimer chrono;
	bool bound=false;
	Field::RandIter G(F);

	Element *A,*B,*C;
	A = FFLAS::fflas_new<Element>(nmax*nmax);
	B = FFLAS::fflas_new<Element>(nmax*nmax);
	C = FFLAS::fflas_new<Element>(nmax*nmax);
	for (size_t i=0; i<nmax*nmax;++i)
		G.random(A[i]);

	for (size_t i=0; i<nmax*nmax;++i)
		G.random(B[i]);

	for (size_t i=0; i<nmax*nmax;++i)
		G.random(C[i]);

	std::ofstream outlog;
	outlog.open("optim.log", std::ofstream::out | std::ofstream::app);
#ifdef __FFLASFFPACK_HAVE_CXX11
    std::time_t result = std::time(NULL);
    outlog << std::endl <<
        "---------------------------------------------------------------------"
           << std::endl << std::asctime(std::localtime(&result));
#endif
	outlog << std::endl
		<< "Threshold for finite field Strassen-Winograd matrix multiplication" ;
	F.write(outlog << "(using ") << ')' << std::endl;
	do {
	double basetime, time;
		FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Winograd> ClassicH(F,0, FFLAS::ParSeqHelper::Sequential());
		FFLAS::MMHelper<Field, FFLAS::MMHelperAlgo::Winograd> WinogradH(F,1, FFLAS::ParSeqHelper::Sequential());

		int iter=3;
		    //warm up computation
		FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
				n, n, n, F.mOne, A, n, B, n, F.one, C, n, ClassicH);
		chrono.start();
		for (int i=0;i<iter;i++)
			FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans, n, n, n, F.mOne, A, n, B, n, F.one, C, n, ClassicH);
		chrono.stop();
		std::cout << std::endl
			<< "fgemm " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS << " Mffops"
			<< std::endl;
		outlog << std::endl
			<< "fgemm " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS << " Mffops"
			<< std::endl;
		basetime= chrono.realtime();
		    //warm up
		FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
			     n, n, n, F.mOne, A, n, B, n, F.one, C, n, WinogradH);
		chrono.clear();
		chrono.start();
		for (int i=0; i<iter; i++)
			FFLAS::fgemm(F, FFLAS::FflasNoTrans, FFLAS::FflasNoTrans,
				     n, n, n, F.mOne, A, n, B,n, F.one, C, n, WinogradH);
		chrono.stop();
		std::cout << "1Wino " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS  << " Mffops"
			<< std::endl;
		outlog << "1Wino " << n << "x" << n << ": "
			<< chrono.realtime()/iter << " s, "
			<< MFLOPS  << " Mffops"
			<< std::endl;
		time= chrono.realtime();

		if (basetime > time ){
			count++;
			if (count > 1){
				nbest=n;
				bound=true;
				prec=prec>>1;
				n-=prec;
			}
		}
		else{
			count=0;
			if (bound)
				prec=prec>>1;
			n+=prec;
		}
	} while ((prec > 64 ) && (n < nmax));

	std::ofstream out("WinoThreshold");
	if (nbest != 0 ) {
	if (typeid(Element).name() == typeid(double).name()) {
		if ( balanced(F) ) {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_BAL"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_BAL" << ' ' <<  nbest << endl;
		}
		else {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD" << ' ' <<  nbest << endl;
		}
		out << "#endif"                               << endl  << endl;
	}

	if (typeid(Element).name() == typeid(float).name()) {
		if ( balanced(F) ) {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_BAL_FLT"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_BAL_FLT" << ' ' << nbest << endl;
		}
		else {
			out << "#ifndef __FFLASFFPACK_WINOTHRESHOLD_FLT"  << endl;
			out << "#define __FFLASFFPACK_WINOTHRESHOLD_FLT" << ' ' << nbest << endl;
		}
		out << "#endif"                               << endl  << endl;
	}
	}
	out.close();

	outlog << "defined __FFLASFFPACK_WINOTHRESHOLD to " << nbest << "" << std::endl;
	outlog.close();

	FFLAS::fflas_delete( A);
	FFLAS::fflas_delete( C);

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>Create new file<commit_after><|endoftext|>


<commit_before>#include <boost/rational.hpp>
#include "bb.hpp"

using namespace std;
using namespace boost;

void inner_bb(vector<item_t>::iterator begin, vector<item_t>::iterator end, const size_t w, const size_t p, const size_t c, const rational<size_t> bi_eff, size_t &bp) {
  // There are no items
  if (begin == end) return;

  // If the solution is invalid or is impossible to get a solution better
  // than the bound from this partial solution, then stop
  if (w > c || p + (c-w)*bi_eff < bp) return;

  // If the solution is valid and better than the bound, update the bound
  if (p > bp) bp = p;

  // Solutions that does not use one more of the item pointed by begin
  inner_bb(begin + 1, end, w, p, c, bi_eff, bp);
  // Solutions that use one more of the item pointed by begin
  inner_bb(begin, end, w + begin->w, p + begin->p, c, bi_eff, bp);
}

void bb(ukp_instance_t &ukpi, ukp_solution_t &sol, bool already_sorted/* = false*/) {
  if (!already_sorted) sort_by_efficiency(ukpi.items);
  const size_t wb = ukpi.items[0].w, pb = ukpi.items[0].p;
  const rational<size_t> bi_eff(pb, wb);

  sol.opt = (ukpi.c/wb)*pb;
  inner_bb(ukpi.items.begin(), ukpi.items.end(), 0, 0, ukpi.c, bi_eff, sol.opt);
}

<commit_msg>Changes in BB UKP, and notes on how to meke it better.<commit_after>#include <boost/rational.hpp>
#include <iostream>
#include "bb.hpp"

using namespace std;
using namespace boost;

/* TODO: Instead of starting at zero elements of some item i,
 * start with the greatest possible quantity of elements of that
 * type, and then decreases the number (if it's greater than zero)
 * This helps mainly because we examine first the solutions with the
 * least of capacity left (most probability of being optimal).
 * TODO: The bound computed is very stupid. The items are already
 * ordered by efficiency, then if the first item can't be used anymore,
 * why use it in the bound? The upper bound over the remaining capacity
 * must be done by using the current (or next) item.
 * TODO: The type of pruning done by MTU/MT2 is a periodicity prunning,
 * if you use n-1 of the least efficient item used and cover the
 * remaining capacity at its fullest (relaxed covering) with the most
 * efficient of the remaining items (that are all less efficient than the
 * current), you can known if the there are possible solution that take
 * less than n items of the best item, this is the same that verifying
 * if for some capacity is more interesting add one more item of i
 * or use the remaining items.
 */

struct bound_info_t {
  size_t bw, bp, bw2, bp2;
  rational<size_t> be3;
};

/* The items must be sorted by nondecreasing efficiency and
 * if tied, by nonincreasing weight, there must be at least 3
 * different items */
void gen_bound_info(const vector<item_t> &items, bound_info_t &bi) {
  bi.bw = items[0].w;
  bi.bp = items[0].p;
  auto it = items.begin() + 1, end = items.end();
  bool f2 = false;
  for (; it < end; ++it) {
    if (it->w < bi.bw) continue;
    if (!f2) {
      f2 = true;
      bi.bw2 = it->w;
      bi.bp2 = it->p;
    } else {
      bi.be3 = rational<size_t>(it->p, it->w);
      break;
    }
  }
}

rational<size_t> lower_bound(size_t c, const bound_info_t &bi) {
  rational<size_t> lb((c/bi.bw)*bi.bp);
  c = c % bi.bw;
  lb += (c/bi.bw2)*bi.bp2;
  c = c % bi.bw2;
  lb += c*bi.be3;

  return lb;
}

item_t heuristic_upper_bound(size_t c, const bound_info_t &bi) {
  item_t i(0, 0);
  i.p += (c/bi.bw)*bi.bp;
  i.w += (c/bi.bw)*bi.bw;
  c = c % bi.bw;
  i.p += (c/bi.bw2)*bi.bp2;
  i.w += (c/bi.bw2)*bi.bw2;
  c = c % bi.bw2;
  i.p += (c/bi.be3.denominator())*bi.be3.numerator();
  i.w += (c/bi.be3.denominator())*bi.be3.denominator();

  return i;
}

void inner_bb(vector<item_t>::iterator begin, vector<item_t>::iterator end, const size_t w_min, const size_t w, const size_t p, const size_t c, const bound_info_t &bi, size_t &bp) {
  // There are no items
  /*cout << "w: " << w << endl;
  cout << "p: " << p << endl;
  cout << "bp: " << bp << endl;
  if (w < c) cout << "pp: " << rational_cast<size_t, size_t>((c-w)*bi_eff) + 1 << endl;
  cout << endl;*/
  if (begin == end) return;

  // If the solution is invalid or is impossible to get a solution better
  // than the bound from this partial solution, then stop
  if (w > c || p + lower_bound(c-w, bi) < bp) return;

  // If the solution is valid and better than the bound, update the bound
  if (p > bp) bp = p;

  // Avoid unnecessary branching
  if (w + w_min > c) return;

  // Solutions that use one more of the item pointed by begin
  inner_bb(begin, end, w_min, w + begin->w, p + begin->p, c, bi, bp);
  // Solutions that does not use one more of the item pointed by begin
  inner_bb(begin + 1, end, w_min, w, p, c, bi, bp);
}

pair<size_t,size_t> minmax_item_weight(vector<item_t> &items) {
  size_t min, max;
  min = max = items[0].w;
  for (auto it = items.begin()+1; it != items.end(); ++it) {
    size_t x = (*it).w;
    if (x < min) min = x;
    else if (x > max) max = x;
  }
  return make_pair(min,max);
}

void bb(ukp_instance_t &ukpi, ukp_solution_t &sol, bool already_sorted/* = false*/) {
  if (!already_sorted) sort_by_efficiency(ukpi.items);
  const auto minw_max = minmax_item_weight(ukpi.items);
  const size_t w_min = minw_max.first, w_max = minw_max.second;

  bound_info_t bi;
  gen_bound_info(ukpi.items, bi);

  item_t ub = heuristic_upper_bound(ukpi.c, bi);

  sol.opt = ub.p;
  inner_bb(ukpi.items.begin(), ukpi.items.end(), w_min, ub.w, ub.p, ukpi.c, bi, sol.opt);
}

<|endoftext|>


<commit_before>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript 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 (at your option) any later version.
 *
 * Cycript 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 Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#ifndef CYCRIPT_EXCEPTION_HPP
#define CYCRIPT_EXCEPTION_HPP

#ifdef CY_EXECUTE
#include <JavaScriptCore/JSBase.h>
#endif

// XXX: does _assert really need this?
#include <errno.h>

#include "Standard.hpp"

class CYPool;

struct CYException {
    virtual ~CYException() {
    }

    virtual const char *PoolCString(CYPool &pool) const = 0;
#ifdef CY_EXECUTE
    virtual JSValueRef CastJSValue(JSContextRef context) const = 0;
#endif
};

void CYThrow(const char *format, ...) _noreturn;

#ifdef CY_EXECUTE
void CYThrow(JSContextRef context, JSValueRef value);
#endif

#define CYTry \
    try
#define CYCatch(value) \
    catch (const CYException &error) { \
        *exception = error.CastJSValue(context); \
        return value; \
    } catch (...) { \
        *exception = CYCastJSValue(context, "catch(...)"); \
        return value; \
    }

// XXX: fix this: _ is not safe; this is /not/ Menes ;P
#undef _assert
#define _assert(test, args...) do { \
    if (!(test)) \
        CYThrow("*** _assert(%s):%s(%u):%s [errno=%d]", #test, __FILE__, __LINE__, __FUNCTION__, errno); \
} while (false)

#define _trace() do { \
    fprintf(stderr, "_trace():%u\n", __LINE__); \
} while (false)

#define _syscall(expr) ({ \
    __typeof__(expr) _value; \
    do if ((long) (_value = (expr)) != -1) \
        break; \
    else switch (errno) { \
        case EINTR: \
            continue; \
        default: \
            _assert(false); \
    } while (true); \
    _value; \
})

#define _aprcall(expr) \
    do { \
        apr_status_t _aprstatus((expr)); \
        _assert(_aprstatus == APR_SUCCESS); \
    } while (false)

#define _krncall(expr) \
    do { \
        kern_return_t _krnstatus((expr)); \
        _assert(_krnstatus == KERN_SUCCESS); \
    } while (false)

#define _sqlcall(expr) ({ \
    __typeof__(expr) _value = (expr); \
    if (_value != 0 && (_value < 100 || _value >= 200)) \
        _assert(false, "_sqlcall(%u:%s): %s\n", _value, #expr, sqlite3_errmsg(database_)); \
    _value; \
})

struct CYJSException {
    JSContextRef context_;
    JSValueRef value_;

    CYJSException(JSContextRef context) :
        context_(context),
        value_(NULL)
    {
    }

    ~CYJSException() {
        CYThrow(context_, value_);
    }

    operator JSValueRef *() {
        return &value_;
    }
};

#define _jsccall(code, args...) ({ \
    CYJSException _error(context); \
    (code)(args, _error); \
})

#endif/*CYCRIPT_ERROR_HPP*/
<commit_msg>Sort of improve the error messages from _assert.<commit_after>/* Cycript - Optimizing JavaScript Compiler/Runtime
 * Copyright (C) 2009-2013  Jay Freeman (saurik)
*/

/* GNU General Public License, Version 3 {{{ */
/*
 * Cycript 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 (at your option) any later version.
 *
 * Cycript 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 Cycript.  If not, see <http://www.gnu.org/licenses/>.
**/
/* }}} */

#ifndef CYCRIPT_EXCEPTION_HPP
#define CYCRIPT_EXCEPTION_HPP

#ifdef CY_EXECUTE
#include <JavaScriptCore/JSBase.h>
#endif

// XXX: does _assert really need this?
#include <errno.h>

#include "Standard.hpp"

class CYPool;

struct CYException {
    virtual ~CYException() {
    }

    virtual const char *PoolCString(CYPool &pool) const = 0;
#ifdef CY_EXECUTE
    virtual JSValueRef CastJSValue(JSContextRef context) const = 0;
#endif
};

void CYThrow(const char *format, ...) _noreturn;

#ifdef CY_EXECUTE
void CYThrow(JSContextRef context, JSValueRef value);
#endif

#define CYTry \
    try
#define CYCatch(value) \
    catch (const CYException &error) { \
        *exception = error.CastJSValue(context); \
        return value; \
    } catch (...) { \
        *exception = CYCastJSValue(context, "catch(...)"); \
        return value; \
    }

#define _assert_(mode, test, code, format, ...) do \
    if (!(test)) \
        CYThrow("*** _%s(%s):%s(%u):%s" format, mode, code, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
while (false)

// XXX: fix this: _ is not safe; this is /not/ Menes ;P
#undef _assert
#define _assert(test) \
    _assert_("assert", (test), #test, "")

#define _trace() do { \
    fprintf(stderr, "_trace():%u\n", __LINE__); \
} while (false)

#define _syscall(expr) ({ \
    __typeof__(expr) _value; \
    do if ((long) (_value = (expr)) != -1) \
        break; \
    else \
        _assert_("syscall", errno == EINTR, #expr, " [errno=%d]", errno); \
    while (true); \
    _value; \
})

#define _aprcall(expr) \
    do { \
        apr_status_t _aprstatus((expr)); \
        _assert_("aprcall", _aprstatus == APR_SUCCESS, #expr, ""); \
    } while (false)

#define _krncall(expr) \
    do { \
        kern_return_t _krnstatus((expr)); \
        _assert_("krncall", _krnstatus == KERN_SUCCESS, #expr, " [return=0x%x]", _krnstatus); \
    } while (false)

#define _sqlcall(expr) ({ \
    __typeof__(expr) _value = (expr); \
    _assert_("sqlcall", _value == 0 || _value >= 100 && _value < 200, #expr, " %u:%s", _value sqlite3_errmsg(database_)); \
})

struct CYJSException {
    JSContextRef context_;
    JSValueRef value_;

    CYJSException(JSContextRef context) :
        context_(context),
        value_(NULL)
    {
    }

    ~CYJSException() {
        CYThrow(context_, value_);
    }

    operator JSValueRef *() {
        return &value_;
    }
};

#define _jsccall(code, args...) ({ \
    CYJSException _error(context); \
    (code)(args, _error); \
})

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


<commit_before>#include "GUIHelper.h"
#include <QDialog>
#include <QApplication>
#include <QFormLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include <QClipboard>
#include <QBarSet>
#include <QBarSeries>
#include <QBarCategoryAxis>
#include <QChartView>
#include <QDebug>
#include <QHeaderView>
#include <QMessageBox>

QT_CHARTS_USE_NAMESPACE

void GUIHelper::showMessage(QString title, QString message, QMap<QString, QString> add_info)
{
	//create dialog
	QDialog* dialog = new QDialog(QApplication::activeWindow());
	dialog->window()->setWindowTitle(title);
	QGridLayout* layout = new QGridLayout();
	dialog->window()->setLayout(layout);

	//add content
	int row = 0;
	layout->addWidget(new QLabel("message:"),row ,0, Qt::AlignLeft|Qt::AlignTop);
	layout->addWidget(new QLabel(message),row ,1);
	foreach(QString key, add_info.keys())
	{
		++row;
		layout->addWidget(new QLabel(key + ":"),row ,0, Qt::AlignLeft|Qt::AlignTop);
		layout->addWidget(new QLabel(add_info[key]),row ,1);
	}

	//show
	dialog->exec();
}

QSharedPointer<QDialog> GUIHelper::createDialog(QWidget* widget, QString title, QString label, bool add_buttons)
{
	QSharedPointer<QDialog> dialog = QSharedPointer<QDialog>(new QDialog(QApplication::activeWindow()));
	dialog->setWindowFlags(Qt::Window);
	dialog->setWindowTitle(title);

	dialog->setLayout(new QBoxLayout(QBoxLayout::TopToBottom));
	dialog->layout()->setMargin(3);
	if (!label.isEmpty())
	{
		QLabel* label_widget = new QLabel(label);
		label_widget->setTextFormat(Qt::RichText);
		dialog->layout()->addWidget(label_widget);
	}
	dialog->layout()->addWidget(widget);

	//add buttons
	if (add_buttons)
	{
		QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
		dialog->connect(button_box, SIGNAL(accepted()), dialog.data(), SLOT(accept()));
		dialog->connect(button_box, SIGNAL(rejected()), dialog.data(), SLOT(reject()));
		dialog->layout()->addWidget(button_box);
	}

	return dialog;
}

void GUIHelper::styleSplitter(QSplitter* splitter)
{
	splitter->setHandleWidth(5);
	if (splitter->orientation()==Qt::Vertical)
	{
		splitter->setStyleSheet("QSplitter::handle:vertical { image: url(:/Icons/Splitter_vertical.png); } ");
	}
	else
	{
		splitter->setStyleSheet("QSplitter::handle:horizontal { image: url(:/Icons/Splitter_horizontal.png); } ");
	}
}

void GUIHelper::resizeTableCells(QTableWidget* widget, int max_col_width, bool first_height_for_all, int rows_used_for_column_width)
{
	//resize columns width
	widget->horizontalHeader()->setResizeContentsPrecision(rows_used_for_column_width);
	widget->resizeColumnsToContents();

	//restrict width
	if (max_col_width>0)
	{
		for (int i=0; i<widget->columnCount(); ++i)
		{
			if (widget->columnWidth(i)>max_col_width)
			{
				widget->setColumnWidth(i, max_col_width);
			}
		}
	}

	//determine row height
	if (first_height_for_all)
	{
		int height = -1;
		for (int i=0; i<widget->rowCount(); ++i)
		{
			if (!widget->isRowHidden(i))
			{
				widget->resizeRowToContents(i);
				height = widget->rowHeight(i);
				break;
			}
		}

		//set row height
		if (height!=-1)
		{
			for (int i=0; i<widget->rowCount(); ++i)
			{
				widget->setRowHeight(i, height);
			}
		}
	}
	else
	{
		widget->resizeRowsToContents();
	}
}

QTableWidgetItem* GUIHelper::createTableItem(const QString& text, Qt::Alignment alignment, bool editable)
{
	QTableWidgetItem* item = new QTableWidgetItem(text);

	item->setTextAlignment(alignment);
	if (!editable)
	{
		item->setFlags(item->flags()& (~Qt::ItemIsEditable));
	}

	return item;
}

QLabel* GUIHelper::createLinkLabel(const QString& text, Qt::Alignment alignment)
{
	QLabel* label = new QLabel();

	label->setMargin(2);
	label->setText(text);
	label->setAlignment(alignment);
	label->setOpenExternalLinks(true);

	return label;
}

QList<int> GUIHelper::selectedTableRows(const QTableWidget* table, bool skip_hidden)
{
	QList<int> output;

	QList<QTableWidgetSelectionRange> ranges = table->selectedRanges();
	foreach(const QTableWidgetSelectionRange& range, ranges)
	{
		for (int r=range.topRow(); r<=range.bottomRow(); ++r)
		{
			if (skip_hidden && table->isRowHidden(r)) continue;
			output << r;
		}
	}

	std::sort(output.begin(), output.end());

	return output;
}

QList<int> GUIHelper::selectedTableColumns(const QTableWidget* table, bool skip_hidden)
{
	QList<int> output;

	foreach(const QTableWidgetSelectionRange& range, table->selectedRanges())
	{
		for (int c=range.leftColumn(); c<=range.rightColumn(); ++c)
		{
			if (skip_hidden && table->isColumnHidden(c)) continue;
			output << c;
		}
	}

	std::sort(output.begin(), output.end());

	return output;
}

void GUIHelper::copyToClipboard(const QTableWidget* table, bool selected_rows_only)
{
	//get selected rows
	QSet<int> selected_rows = selectedTableRows(table).toSet();

	//header
	QString output = "#";
	for (int col=0; col<table->columnCount(); ++col)
	{
		if (col!=0) output += '\t';
		output += table->horizontalHeaderItem(col)->text().replace('\t', ' ').replace('\n', ' ').replace('\r', ' ').trimmed();
	}
	output += '\n';

	//rows
	for (int row=0; row<table->rowCount(); ++row)
	{
		if (table->isRowHidden(row)) continue;

		if (selected_rows_only && !selected_rows.contains(row)) continue;

		for (int col=0; col<table->columnCount(); ++col)
		{
			if (col!=0) output += '\t';

			QString text = "";
			QTableWidgetItem* item  = table->item(row, col);
			if (item!=nullptr)
			{
				text = item->text();
			}
			else
			{
				QWidget* cell_widget = table->cellWidget(row, col);
				if (cell_widget!=nullptr)
				{
					if (cell_widget->inherits("QLabel"))
					{
						text = qobject_cast<QLabel*>(cell_widget)->text();
					}
					else
					{
						qDebug() << "Unhandled table item type " + QString(cell_widget->metaObject()->className()) + " in copyToClipboard!";
					}
				}
			}
			output += text.replace('\t', ' ').replace('\n', ' ').replace('\r', ' ').trimmed();
		}
		output += '\n';
	}

	QApplication::clipboard()->setText(output);
}

QFrame* GUIHelper::horizontalLine()
{
	QFrame* line = new QFrame();
	line->setObjectName("line");
	line->setFrameShape(QFrame::HLine);
	line->setFrameShadow(QFrame::Sunken);
	line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
	line->setMinimumHeight(3);
	return line;
}

QChartView* GUIHelper::histogramChart(const Histogram& hist, QString title)
{
	QBarSet* set = new QBarSet(title);
	for(int bin=0; bin<hist.binCount(); ++bin)
	{
		set->append(hist.binValue(bin, true));
	}

	QBarSeries* series = new QBarSeries();
	series->append(set);
	QChart* chart = new QChart();
	chart->addSeries(series);
	chart->legend()->setVisible(false);
	chart->createDefaultAxes();
	chart->axisY()->setTitleText("%");
	QBarCategoryAxis* x_axis = new QBarCategoryAxis();
	for(int bin=0; bin<hist.binCount(); ++bin)
	{
		double start = hist.startOfBin(bin);
		x_axis->append(QString::number(start, 'f', 2) + "-" + QString::number(start+hist.binSize(), 'f', 2));
	}
	x_axis->setTitleText(title);
	x_axis->setLabelsAngle(90);
	chart->setAxisX(x_axis);

	QChartView* view = new QChartView(chart);
	view->setRenderHint(QPainter::Antialiasing);
	view->setMinimumSize(1000, 800);

	return view;
}

QCompleter*GUIHelper::completer(QObject* parent, const QStringList& items)
{
	QCompleter* completer = new QCompleter(items, parent);

	completer->setCompletionMode(QCompleter::PopupCompletion);
	completer->setCaseSensitivity(Qt::CaseInsensitive);
	completer->setFilterMode(Qt::MatchContains);
	completer->setCompletionRole(Qt::DisplayRole);

	return completer;
}

QString GUIHelper::colorToQssFormat(const QColor& color)
{
	return QString("rgba(%1, %2, %3, %4)")
			.arg(color.red())
			.arg(color.green())
			.arg(color.blue())
			.arg(color.alpha());
}

void GUIHelper::showException(QWidget* parent, Exception& e, QString title)
{
	//reset override cursor
	while(QApplication::overrideCursor()!=nullptr)
	{
		qDebug() << __LINE__ << QApplication::overrideCursor();
		QApplication::restoreOverrideCursor();
	}

	//show dialog to user
	if (e.type()==ExceptionType::CRITIAL)
	{
		QMessageBox::critical(parent, title, "Critical error - this should probably not happen:\n" + e.message());
	}
	else if (e.type()==ExceptionType::WARNING)
	{
		QMessageBox::warning(parent, title, e.message());
	}
	else
	{
		QMessageBox::information(parent, title, e.message());
	}
}

<commit_msg>removed debug output.<commit_after>#include "GUIHelper.h"
#include <QDialog>
#include <QApplication>
#include <QFormLayout>
#include <QLabel>
#include <QDialogButtonBox>
#include <QClipboard>
#include <QBarSet>
#include <QBarSeries>
#include <QBarCategoryAxis>
#include <QChartView>
#include <QDebug>
#include <QHeaderView>
#include <QMessageBox>

QT_CHARTS_USE_NAMESPACE

void GUIHelper::showMessage(QString title, QString message, QMap<QString, QString> add_info)
{
	//create dialog
	QDialog* dialog = new QDialog(QApplication::activeWindow());
	dialog->window()->setWindowTitle(title);
	QGridLayout* layout = new QGridLayout();
	dialog->window()->setLayout(layout);

	//add content
	int row = 0;
	layout->addWidget(new QLabel("message:"),row ,0, Qt::AlignLeft|Qt::AlignTop);
	layout->addWidget(new QLabel(message),row ,1);
	foreach(QString key, add_info.keys())
	{
		++row;
		layout->addWidget(new QLabel(key + ":"),row ,0, Qt::AlignLeft|Qt::AlignTop);
		layout->addWidget(new QLabel(add_info[key]),row ,1);
	}

	//show
	dialog->exec();
}

QSharedPointer<QDialog> GUIHelper::createDialog(QWidget* widget, QString title, QString label, bool add_buttons)
{
	QSharedPointer<QDialog> dialog = QSharedPointer<QDialog>(new QDialog(QApplication::activeWindow()));
	dialog->setWindowFlags(Qt::Window);
	dialog->setWindowTitle(title);

	dialog->setLayout(new QBoxLayout(QBoxLayout::TopToBottom));
	dialog->layout()->setMargin(3);
	if (!label.isEmpty())
	{
		QLabel* label_widget = new QLabel(label);
		label_widget->setTextFormat(Qt::RichText);
		dialog->layout()->addWidget(label_widget);
	}
	dialog->layout()->addWidget(widget);

	//add buttons
	if (add_buttons)
	{
		QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
		dialog->connect(button_box, SIGNAL(accepted()), dialog.data(), SLOT(accept()));
		dialog->connect(button_box, SIGNAL(rejected()), dialog.data(), SLOT(reject()));
		dialog->layout()->addWidget(button_box);
	}

	return dialog;
}

void GUIHelper::styleSplitter(QSplitter* splitter)
{
	splitter->setHandleWidth(5);
	if (splitter->orientation()==Qt::Vertical)
	{
		splitter->setStyleSheet("QSplitter::handle:vertical { image: url(:/Icons/Splitter_vertical.png); } ");
	}
	else
	{
		splitter->setStyleSheet("QSplitter::handle:horizontal { image: url(:/Icons/Splitter_horizontal.png); } ");
	}
}

void GUIHelper::resizeTableCells(QTableWidget* widget, int max_col_width, bool first_height_for_all, int rows_used_for_column_width)
{
	//resize columns width
	widget->horizontalHeader()->setResizeContentsPrecision(rows_used_for_column_width);
	widget->resizeColumnsToContents();

	//restrict width
	if (max_col_width>0)
	{
		for (int i=0; i<widget->columnCount(); ++i)
		{
			if (widget->columnWidth(i)>max_col_width)
			{
				widget->setColumnWidth(i, max_col_width);
			}
		}
	}

	//determine row height
	if (first_height_for_all)
	{
		int height = -1;
		for (int i=0; i<widget->rowCount(); ++i)
		{
			if (!widget->isRowHidden(i))
			{
				widget->resizeRowToContents(i);
				height = widget->rowHeight(i);
				break;
			}
		}

		//set row height
		if (height!=-1)
		{
			for (int i=0; i<widget->rowCount(); ++i)
			{
				widget->setRowHeight(i, height);
			}
		}
	}
	else
	{
		widget->resizeRowsToContents();
	}
}

QTableWidgetItem* GUIHelper::createTableItem(const QString& text, Qt::Alignment alignment, bool editable)
{
	QTableWidgetItem* item = new QTableWidgetItem(text);

	item->setTextAlignment(alignment);
	if (!editable)
	{
		item->setFlags(item->flags()& (~Qt::ItemIsEditable));
	}

	return item;
}

QLabel* GUIHelper::createLinkLabel(const QString& text, Qt::Alignment alignment)
{
	QLabel* label = new QLabel();

	label->setMargin(2);
	label->setText(text);
	label->setAlignment(alignment);
	label->setOpenExternalLinks(true);

	return label;
}

QList<int> GUIHelper::selectedTableRows(const QTableWidget* table, bool skip_hidden)
{
	QList<int> output;

	QList<QTableWidgetSelectionRange> ranges = table->selectedRanges();
	foreach(const QTableWidgetSelectionRange& range, ranges)
	{
		for (int r=range.topRow(); r<=range.bottomRow(); ++r)
		{
			if (skip_hidden && table->isRowHidden(r)) continue;
			output << r;
		}
	}

	std::sort(output.begin(), output.end());

	return output;
}

QList<int> GUIHelper::selectedTableColumns(const QTableWidget* table, bool skip_hidden)
{
	QList<int> output;

	foreach(const QTableWidgetSelectionRange& range, table->selectedRanges())
	{
		for (int c=range.leftColumn(); c<=range.rightColumn(); ++c)
		{
			if (skip_hidden && table->isColumnHidden(c)) continue;
			output << c;
		}
	}

	std::sort(output.begin(), output.end());

	return output;
}

void GUIHelper::copyToClipboard(const QTableWidget* table, bool selected_rows_only)
{
	//get selected rows
	QSet<int> selected_rows = selectedTableRows(table).toSet();

	//header
	QString output = "#";
	for (int col=0; col<table->columnCount(); ++col)
	{
		if (col!=0) output += '\t';
		output += table->horizontalHeaderItem(col)->text().replace('\t', ' ').replace('\n', ' ').replace('\r', ' ').trimmed();
	}
	output += '\n';

	//rows
	for (int row=0; row<table->rowCount(); ++row)
	{
		if (table->isRowHidden(row)) continue;

		if (selected_rows_only && !selected_rows.contains(row)) continue;

		for (int col=0; col<table->columnCount(); ++col)
		{
			if (col!=0) output += '\t';

			QString text = "";
			QTableWidgetItem* item  = table->item(row, col);
			if (item!=nullptr)
			{
				text = item->text();
			}
			else
			{
				QWidget* cell_widget = table->cellWidget(row, col);
				if (cell_widget!=nullptr)
				{
					if (cell_widget->inherits("QLabel"))
					{
						text = qobject_cast<QLabel*>(cell_widget)->text();
					}
					else
					{
						qDebug() << "Unhandled table item type " + QString(cell_widget->metaObject()->className()) + " in copyToClipboard!";
					}
				}
			}
			output += text.replace('\t', ' ').replace('\n', ' ').replace('\r', ' ').trimmed();
		}
		output += '\n';
	}

	QApplication::clipboard()->setText(output);
}

QFrame* GUIHelper::horizontalLine()
{
	QFrame* line = new QFrame();
	line->setObjectName("line");
	line->setFrameShape(QFrame::HLine);
	line->setFrameShadow(QFrame::Sunken);
	line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
	line->setMinimumHeight(3);
	return line;
}

QChartView* GUIHelper::histogramChart(const Histogram& hist, QString title)
{
	QBarSet* set = new QBarSet(title);
	for(int bin=0; bin<hist.binCount(); ++bin)
	{
		set->append(hist.binValue(bin, true));
	}

	QBarSeries* series = new QBarSeries();
	series->append(set);
	QChart* chart = new QChart();
	chart->addSeries(series);
	chart->legend()->setVisible(false);
	chart->createDefaultAxes();
	chart->axisY()->setTitleText("%");
	QBarCategoryAxis* x_axis = new QBarCategoryAxis();
	for(int bin=0; bin<hist.binCount(); ++bin)
	{
		double start = hist.startOfBin(bin);
		x_axis->append(QString::number(start, 'f', 2) + "-" + QString::number(start+hist.binSize(), 'f', 2));
	}
	x_axis->setTitleText(title);
	x_axis->setLabelsAngle(90);
	chart->setAxisX(x_axis);

	QChartView* view = new QChartView(chart);
	view->setRenderHint(QPainter::Antialiasing);
	view->setMinimumSize(1000, 800);

	return view;
}

QCompleter*GUIHelper::completer(QObject* parent, const QStringList& items)
{
	QCompleter* completer = new QCompleter(items, parent);

	completer->setCompletionMode(QCompleter::PopupCompletion);
	completer->setCaseSensitivity(Qt::CaseInsensitive);
	completer->setFilterMode(Qt::MatchContains);
	completer->setCompletionRole(Qt::DisplayRole);

	return completer;
}

QString GUIHelper::colorToQssFormat(const QColor& color)
{
	return QString("rgba(%1, %2, %3, %4)")
			.arg(color.red())
			.arg(color.green())
			.arg(color.blue())
			.arg(color.alpha());
}

void GUIHelper::showException(QWidget* parent, Exception& e, QString title)
{
	//reset override cursor
	while(QApplication::overrideCursor()!=nullptr)
	{
		QApplication::restoreOverrideCursor();
	}

	//show dialog to user
	if (e.type()==ExceptionType::CRITIAL)
	{
		QMessageBox::critical(parent, title, "Critical error - this should probably not happen:\n" + e.message());
	}
	else if (e.type()==ExceptionType::WARNING)
	{
		QMessageBox::warning(parent, title, e.message());
	}
	else
	{
		QMessageBox::information(parent, title, e.message());
	}
}

<|endoftext|>


<commit_before>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/operators/assign_value_op.h"

namespace paddle {
namespace operators {

class AssignValueOp : public framework::OperatorWithKernel {
 public:
  AssignValueOp(const std::string &type,
                const framework::VariableNameMap &inputs,
                const framework::VariableNameMap &outputs,
                const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of AssignValueOp should not be null.");
    auto shape = ctx->Attrs().Get<std::vector<int>>("shape");
    ctx->SetOutputDim("Out", framework::make_ddim(shape));
  }

 protected:
  framework::OpKernelType GetActualKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::proto::DataType(ctx.Attr<int>("dtype")), ctx.GetPlace());
  }
};

class AssignValueOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  AssignValueOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddOutput("Out", "(Tensor) Output tensor of assign_value operator.");
    AddAttr<std::vector<int>>("shape",
                              "(vector<int>) "
                              "Shape of values.");
    AddAttr<int>("dtype", "data type of values")
        .InEnum({framework::proto::DataType::INT32,
                 framework::proto::DataType::FP32});
    AddAttr<std::vector<float>>("fp32_values", "store the float values")
        .SetDefault({});
    AddAttr<std::vector<int>>("int32_values", "store the int values")
        .SetDefault({});
    AddComment(R"DOC(
AssignValue operator

$$Out = values$$
)DOC");
  }
};

template <typename T>
class AssignValueCPUKernel : public AssignValueKernel<T> {
 protected:
  virtual void Copy(void *dst, const void *src, size_t size,
                    const framework::ExecutionContext &ctx) const {
    std::memcpy(dst, src, size);
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OPERATOR(assign_value, ops::AssignValueOp, ops::AssignValueOpMaker);
REGISTER_OP_CPU_KERNEL(assign_value, ops::AssignValueCPUKernel<int>,
                       ops::AssignValueCPUKernel<float>)
<commit_msg>GetActualKernelType => GetExpectedKernelType<commit_after>/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserve.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

#include "paddle/operators/assign_value_op.h"

namespace paddle {
namespace operators {

class AssignValueOp : public framework::OperatorWithKernel {
 public:
  AssignValueOp(const std::string &type,
                const framework::VariableNameMap &inputs,
                const framework::VariableNameMap &outputs,
                const framework::AttributeMap &attrs)
      : OperatorWithKernel(type, inputs, outputs, attrs) {}

  void InferShape(framework::InferShapeContext *ctx) const override {
    PADDLE_ENFORCE(ctx->HasOutput("Out"),
                   "Output(Out) of AssignValueOp should not be null.");
    auto shape = ctx->Attrs().Get<std::vector<int>>("shape");
    ctx->SetOutputDim("Out", framework::make_ddim(shape));
  }

 protected:
  framework::OpKernelType GetExpectedKernelType(
      const framework::ExecutionContext &ctx) const override {
    return framework::OpKernelType(
        framework::proto::DataType(ctx.Attr<int>("dtype")), ctx.GetPlace());
  }
};

class AssignValueOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  AssignValueOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddOutput("Out", "(Tensor) Output tensor of assign_value operator.");
    AddAttr<std::vector<int>>("shape",
                              "(vector<int>) "
                              "Shape of values.");
    AddAttr<int>("dtype", "data type of values")
        .InEnum({framework::proto::DataType::INT32,
                 framework::proto::DataType::FP32});
    AddAttr<std::vector<float>>("fp32_values", "store the float values")
        .SetDefault({});
    AddAttr<std::vector<int>>("int32_values", "store the int values")
        .SetDefault({});
    AddComment(R"DOC(
AssignValue operator

$$Out = values$$
)DOC");
  }
};

template <typename T>
class AssignValueCPUKernel : public AssignValueKernel<T> {
 protected:
  virtual void Copy(void *dst, const void *src, size_t size,
                    const framework::ExecutionContext &ctx) const {
    std::memcpy(dst, src, size);
  }
};

}  // namespace operators
}  // namespace paddle

namespace ops = paddle::operators;

REGISTER_OPERATOR(assign_value, ops::AssignValueOp, ops::AssignValueOpMaker);
REGISTER_OP_CPU_KERNEL(assign_value, ops::AssignValueCPUKernel<int>,
                       ops::AssignValueCPUKernel<float>)
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	シェル：FatFs を利用したシェル風コマンド群 @n
			FileSystem コマンド解析、実行 @n
			・dir [xxx] @n
			・pwd @n
			・cd [xxx] @n
			・free
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/file_io.hpp"
#include "common/format.hpp"

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  command class
		@param[in]	CMD		コマンド入力
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CMD>
	class shell {

		CMD&	cmd_;

		bool	sdc_state_;

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		shell(CMD& cmd) : cmd_(cmd), sdc_state_(true)
		{ }

        //-----------------------------------------------------------------//
        /*!
            @brief  ＳＤ操作の完了を取得
			@return ＳＤ操作が正常なら「true」
        */
        //-----------------------------------------------------------------//
		bool get_status() const { return sdc_state_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  基本ＦＳ操作コマンド解析
			@return ＦＳ操作にマッチしたら「true」
        */
        //-----------------------------------------------------------------//
		bool analize() noexcept
		{
            auto cmdn = cmd_.get_words();
            if(cmdn >= 1) {
                if(cmd_.cmp_word(0, "dir")) {  // dir [xxx]
					char tmp[FF_MAX_LFN + 1];
					if(cmdn == 1) {
						if(!utils::file_io::pwd(tmp, sizeof(tmp))) {
							sdc_state_ = false;
						} else {
							sdc_state_ = utils::file_io::dir(tmp);
						}
					} else {
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_state_ = utils::file_io::dir(tmp);
					}
				} else if(cmd_.cmp_word(0, "pwd")) {  // pwd
					char tmp[FF_MAX_LFN + 1];
					if(!utils::file_io::pwd(tmp, sizeof(tmp))) {
						sdc_state_ = false;
					} else {
						utils::format("%s\n") % tmp;
					}
				} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
					char tmp[FF_MAX_LFN + 1];
					if(cmdn == 1) {
						strcpy(tmp, "/");
					} else {
						cmd_.get_word(1, tmp, sizeof(tmp));
					}
					sdc_state_ = utils::file_io::cd(tmp);
				} else if(cmd_.cmp_word(0, "free")) {  // free
					uint32_t fre;
					uint32_t max;
					if(utils::file_io::get_free_space(fre, max)) {
						uint32_t rate = fre * 1000 / max;
						utils::format("%u/%u [KB] (%u.%u%%)\n")
							% fre % max % (rate / 10) % (rate % 10);
						sdc_state_ = true;
					} else {
						sdc_state_ = false;
					}
				} else {
					return false;
				}
			}
			return true;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  HELP 表示
        */
        //-----------------------------------------------------------------//
		void help() const {
			utils::format("    dir [xxx]       list current directory\n");
			utils::format("    pwd             current directory path\n");
			utils::format("    cd [xxx]        change current directory\n");
			utils::format("    free            list disk space\n");
///						   ---+---+---+---+---+
		}
	};
}
<commit_msg>Update: ls command<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	シェル：FatFs を利用したシェル風コマンド群 @n
			FileSystem コマンド解析、実行 @n
			・dir [xxx] @n
			・pwd @n
			・cd [xxx] @n
			・free
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2019, 2020 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/file_io.hpp"
#include "common/format.hpp"
#include "common/string_utils.hpp"

namespace utils {

    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
    /*!
        @brief  command class
		@param[in]	CMD		コマンド入力
    */
    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class CMD>
	class shell {

		CMD&	cmd_;

		bool	state_;

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		shell(CMD& cmd) : cmd_(cmd), state_(true)
		{ }

        //-----------------------------------------------------------------//
        /*!
            @brief  ＳＤ操作の完了を取得
			@return ＳＤ操作が正常なら「true」
        */
        //-----------------------------------------------------------------//
		bool get_status() const { return state_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  基本ＦＳ操作コマンド解析
			@return ＦＳ操作にマッチしたら「true」
        */
        //-----------------------------------------------------------------//
		bool analize() noexcept
		{
            auto cmdn = cmd_.get_words();
            if(cmdn >= 1) {
                if(cmd_.cmp_word(0, "ls")) {  // ls [xxx]
					char tmp[FF_MAX_LFN + 1];
					if(cmdn == 1) {
						if(!utils::file_io::pwd(tmp, sizeof(tmp))) {
							state_ = false;
						} else {
							state_ = utils::file_io::dir(tmp);
						}
					} else {
						cmd_.get_word(1, tmp, sizeof(tmp));
						state_ = utils::file_io::dir(tmp);
					}
				} else if(cmd_.cmp_word(0, "pwd")) {  // pwd
					char tmp[FF_MAX_LFN + 1];
					if(!utils::file_io::pwd(tmp, sizeof(tmp))) {
						state_ = false;
					} else {
						utils::format("%s\n") % tmp;
					}
				} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
					char tmp[FF_MAX_LFN + 1];
					if(cmdn == 1) {
						strcpy(tmp, "/");
					} else {
						cmd_.get_word(1, tmp, sizeof(tmp));
					}
					state_ = utils::file_io::cd(tmp);
				} else if(cmd_.cmp_word(0, "free")) {  // free
					uint32_t fre;
					uint32_t max;
					if(utils::file_io::get_free_space(fre, max)) {
						uint32_t rate = fre * 1000 / max;
						utils::format("%u/%u [KB] (%u.%u%%)\n")
							% fre % max % (rate / 10) % (rate % 10);
						state_ = true;
					} else {
						state_ = false;
					}
				} else {
					return false;
				}
			}
			return true;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  HELP 表示
			@param[in]	spc0	初期空白数
			@param[in]	spc1	コマンド群文字数
        */
        //-----------------------------------------------------------------//
		void help(int spc0 = 4, int spc1 = 20) const {
			static const char* t[] = {
				"ls [xxx]", "list current directory (-l: long)",
				"pwd",      "current directory path",
				"cd [xxx]", "change current directory",
				"free",     "list disk space",
			};
			for(int i = 0; i < 4; ++i) {
				for(int n = 0; n < spc0; ++n) {
					utils::format(" ");
				}
				utils::format("%s") % t[i * 2];
				int n = strlen(t[i * 2]);
				while(n < spc1) { utils::format(" "); ++n; }
				utils::format("%s\n") % t[i * 2 + 1];
			}
		}
	};
}
<|endoftext|>


<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "timing.h"
#include <algorithm>
#include <unordered_map>
#include <utility>
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

typedef std::unordered_map<const PortInfo *, delay_t> UpdateMap;
typedef std::list<const PortRef *> PortRefList;

static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack, UpdateMap *updates,
                          delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path);

// Follow a path, returning budget to annotate
static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, delay_t slack, UpdateMap *updates,
                                delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path)
{
    delay_t value;
    if (ctx->getPortClock(user.cell, user.port) != IdString()) {
        // At the end of a timing path (arguably, should check setup time
        // here too)
        value = slack / path_length;
        if (slack < min_slack) {
            min_slack = slack;
            if (crit_path)
                *crit_path = *current_path;
        }
    } else {
        // Default to the path ending here, if no further paths found
        value = slack / path_length;
        // Follow outputs of the user
        for (auto port : user.cell->ports) {
            if (port.second.type == PORT_OUT) {
                delay_t comb_delay;
                // Look up delay through this path
                bool is_path = ctx->getCellDelay(user.cell, user.port, port.first, comb_delay);
                if (is_path) {
                    NetInfo *net = port.second.net;
                    if (net) {
                        delay_t path_budget = follow_net(ctx, net, path_length, slack - comb_delay, updates, min_slack,
                                                         current_path, crit_path);
                        value = std::min(value, path_budget);
                    }
                }
            }
        }
    }

    if (updates) {
        auto ret = updates->emplace(&user.cell->ports.at(user.port), value);
        if (!ret.second)
            ret.first->second = std::min(value, ret.first->second);
    }
    return value;
}

static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack, UpdateMap *updates,
                          delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path)
{
    delay_t net_budget = slack / (path_length + 1);
    for (unsigned i = 0; i < net->users.size(); ++i) {
        auto &usr = net->users[i];
        if (crit_path)
            current_path->push_back(&usr);
        net_budget = std::min(net_budget,
                              follow_user_port(ctx, usr, path_length + 1, slack - ctx->getNetinfoRouteDelay(net, i),
                                               updates, min_slack, current_path, crit_path));
        if (crit_path)
            current_path->pop_back();
    }
    return net_budget;
}

static delay_t compute_min_slack(Context *ctx, UpdateMap *updates, PortRefList *crit_path)
{
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    delay_t min_slack = default_slack;

    PortRefList current_path;

    // Go through all clocked drivers and distribute the available path
    //   slack evenly into the budget of every sink on the path ---
    //   record this value into the UpdateMap
    for (auto &cell : ctx->cells) {
        for (auto port : cell.second->ports) {
            if (port.second.type == PORT_OUT) {
                IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first);
                if (clock_domain != IdString()) {
                    delay_t slack = default_slack; // TODO: clock constraints
                    delay_t clkToQ;
                    if (ctx->getCellDelay(cell.second.get(), clock_domain, port.first, clkToQ))
                        slack -= clkToQ;
                    if (port.second.net)
                        follow_net(ctx, port.second.net, 0, slack, updates, min_slack, &current_path, crit_path);
                }
            }
        }
    }

    return min_slack;
}

void assign_budget(Context *ctx)
{
    log_break();
    log_info("Annotating ports with timing budgets\n");
    // Clear delays to a very high value first
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    for (auto &net : ctx->nets) {
        for (auto &usr : net.second->users) {
            usr.budget = default_slack;
        }
    }

    UpdateMap updates;
    delay_t min_slack = compute_min_slack(ctx, &updates, nullptr);

    // If user has not specified a frequency, adjust the target frequency
    //   to be equivalent to the estimate Fmax
    if (!ctx->user_freq) {
        ctx->target_freq = 1e12 / (default_slack - min_slack);
        if (ctx->verbose)
            log_info("minimum slack for this assign = %d, target Fmax for next update = %.2f MHz\n", min_slack,
                     ctx->target_freq / 1e6);
    }

    // Update the budgets
    for (auto &net : ctx->nets) {
        for (size_t i = 0; i < net.second->users.size(); ++i) {
            auto &user = net.second->users[i];
            auto pi = &user.cell->ports.at(user.port);
            auto it = updates.find(pi);
            if (it == updates.end())
                continue;
            user.budget = ctx->getNetinfoRouteDelay(net.second.get(), i) - it->second;

            // Post-update check
            if (ctx->user_freq && user.budget < 0)
                log_warning("port %s.%s, connected to net '%s', has negative "
                            "timing budget of %fns\n",
                            user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                            ctx->getDelayNS(user.budget));
            if (ctx->verbose)
                log_info("port %s.%s, connected to net '%s', has "
                         "timing budget of %fns\n",
                         user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                         ctx->getDelayNS(user.budget));
        }
    }

    log_info("Checksum: 0x%08x\n", ctx->checksum());
}

void update_budget(Context *ctx)
{
    UpdateMap updates;
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    delay_t min_slack = compute_min_slack(ctx, &updates, nullptr);

    // If user has not specified a frequency, adjust the frequency dynamically:
    if (!ctx->user_freq) {
        if (min_slack < 0)
            ctx->target_freq = 1e12 / (default_slack - 0.99 * min_slack);
        else
            ctx->target_freq = 1e12 / (default_slack - 1.05 * min_slack);
        if (ctx->verbose)
            log_info("minimum slack for this update = %d, target Fmax for next update = %.2f MHz\n", min_slack,
                     ctx->target_freq / 1e6);
    }

    // Update the budgets
    for (auto &net : ctx->nets) {
        for (size_t i = 0; i < net.second->users.size(); ++i) {
            auto &user = net.second->users[i];
            auto pi = &user.cell->ports.at(user.port);
            auto it = updates.find(pi);
            if (it == updates.end())
                continue;
            user.budget = ctx->getNetinfoRouteDelay(net.second.get(), i) + it->second;

            // Post-update check
            if (ctx->verbose) {
                if (ctx->user_freq && user.budget < 0)
                    log_warning("port %s.%s, connected to net '%s', has negative "
                                "timing budget of %fns\n",
                                user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                                ctx->getDelayNS(user.budget));
                else
                    log_info("port %s.%s, connected to net '%s', has "
                             "timing budget of %fns\n",
                             user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                             ctx->getDelayNS(user.budget));
            }
        }
    }
}

void compute_fmax(Context *ctx, bool print_fmax, bool print_path)
{
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    PortRefList crit_path;
    delay_t min_slack = compute_min_slack(ctx, nullptr, &crit_path);
    if (print_path) {
        delay_t total = 0;
        log_break();
        log_info("Critical path report:\n");
        log_info("curr total\n");
        auto &front = crit_path.front();
        auto &front_port = front->cell->ports.at(front->port);
        auto &front_driver = front_port.net->driver;
        auto last_port = ctx->getPortClock(front_driver.cell, front_driver.port);
        for (auto sink : crit_path) {
            auto sink_cell = sink->cell;
            auto &port = sink_cell->ports.at(sink->port);
            auto net = port.net;
            unsigned i = 0;
            for (auto &usr : net->users)
                if (&usr == sink)
                    break;
            auto &driver = net->driver;
            auto driver_cell = driver.cell;
            delay_t comb_delay;
            ctx->getCellDelay(sink_cell, last_port, driver.port, comb_delay);
            total += comb_delay;
            log_info("%4d %4d  Source %s.%s\n", comb_delay, total, driver_cell->name.c_str(ctx),
                     driver.port.c_str(ctx));
            delay_t net_delay = ctx->getNetinfoRouteDelay(net, i);
            total += net_delay;
            auto driver_loc = ctx->getBelLocation(driver_cell->bel);
            auto sink_loc = ctx->getBelLocation(sink_cell->bel);
            log_info("%4d %4d    Net %s budget %d (%d,%d) -> (%d,%d)\n", net_delay, total, net->name.c_str(ctx),
                     sink->budget, driver_loc.x, driver_loc.y, sink_loc.x, sink_loc.y);
            log_info("                Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
            last_port = sink->port;
        }
        log_break();
    }
    if (print_fmax)
        log_info("estimated Fmax = %.2f MHz\n", 1e6 / (default_slack - min_slack));
}

NEXTPNR_NAMESPACE_END
<commit_msg>Fix budget realloc<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "timing.h"
#include <algorithm>
#include <unordered_map>
#include <utility>
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

typedef std::unordered_map<const PortInfo *, delay_t> UpdateMap;
typedef std::list<const PortRef *> PortRefList;

static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack, UpdateMap *updates,
                          delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path);

// Follow a path, returning budget to annotate
static delay_t follow_user_port(Context *ctx, PortRef &user, int path_length, delay_t slack, UpdateMap *updates,
                                delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path)
{
    delay_t value;
    if (ctx->getPortClock(user.cell, user.port) != IdString()) {
        // At the end of a timing path (arguably, should check setup time
        // here too)
        value = slack / path_length;
        if (slack < min_slack) {
            min_slack = slack;
            if (crit_path)
                *crit_path = *current_path;
        }
    } else {
        // Default to the path ending here, if no further paths found
        value = slack / path_length;
        // Follow outputs of the user
        for (auto port : user.cell->ports) {
            if (port.second.type == PORT_OUT) {
                delay_t comb_delay;
                // Look up delay through this path
                bool is_path = ctx->getCellDelay(user.cell, user.port, port.first, comb_delay);
                if (is_path) {
                    NetInfo *net = port.second.net;
                    if (net) {
                        delay_t path_budget = follow_net(ctx, net, path_length, slack - comb_delay, updates, min_slack,
                                                         current_path, crit_path);
                        value = std::min(value, path_budget);
                    }
                }
            }
        }
    }

    if (updates) {
        auto ret = updates->emplace(&user.cell->ports.at(user.port), value);
        if (!ret.second)
            ret.first->second = std::min(value, ret.first->second);
    }
    return value;
}

static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, delay_t slack, UpdateMap *updates,
                          delay_t &min_slack, PortRefList *current_path, PortRefList *crit_path)
{
    delay_t net_budget = slack / (path_length + 1);
    for (unsigned i = 0; i < net->users.size(); ++i) {
        auto &usr = net->users[i];
        if (crit_path)
            current_path->push_back(&usr);
        net_budget = std::min(net_budget,
                              follow_user_port(ctx, usr, path_length + 1, slack - ctx->getNetinfoRouteDelay(net, i),
                                               updates, min_slack, current_path, crit_path));
        if (crit_path)
            current_path->pop_back();
    }
    return net_budget;
}

static delay_t compute_min_slack(Context *ctx, UpdateMap *updates, PortRefList *crit_path)
{
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    delay_t min_slack = default_slack;

    PortRefList current_path;

    // Go through all clocked drivers and distribute the available path
    //   slack evenly into the budget of every sink on the path ---
    //   record this value into the UpdateMap
    for (auto &cell : ctx->cells) {
        for (auto port : cell.second->ports) {
            if (port.second.type == PORT_OUT) {
                IdString clock_domain = ctx->getPortClock(cell.second.get(), port.first);
                if (clock_domain != IdString()) {
                    delay_t slack = default_slack; // TODO: clock constraints
                    delay_t clkToQ;
                    if (ctx->getCellDelay(cell.second.get(), clock_domain, port.first, clkToQ))
                        slack -= clkToQ;
                    if (port.second.net)
                        follow_net(ctx, port.second.net, 0, slack, updates, min_slack, &current_path, crit_path);
                }
            }
        }
    }

    return min_slack;
}

void assign_budget(Context *ctx)
{
    log_break();
    log_info("Annotating ports with timing budgets\n");
    // Clear delays to a very high value first
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    for (auto &net : ctx->nets) {
        for (auto &usr : net.second->users) {
            usr.budget = default_slack;
        }
    }

    UpdateMap updates;
    delay_t min_slack = compute_min_slack(ctx, &updates, nullptr);

    // If user has not specified a frequency, adjust the target frequency
    //   to be equivalent to the estimate Fmax
    if (!ctx->user_freq) {
        ctx->target_freq = 1e12 / (default_slack - min_slack);
        if (ctx->verbose)
            log_info("minimum slack for this assign = %d, target Fmax for next update = %.2f MHz\n", min_slack,
                     ctx->target_freq / 1e6);
    }

    // Update the budgets
    for (auto &net : ctx->nets) {
        for (size_t i = 0; i < net.second->users.size(); ++i) {
            auto &user = net.second->users[i];
            auto pi = &user.cell->ports.at(user.port);
            auto it = updates.find(pi);
            if (it == updates.end())
                continue;
            user.budget = ctx->getNetinfoRouteDelay(net.second.get(), i) - it->second;

            // Post-update check
            if (ctx->user_freq && user.budget < 0)
                log_warning("port %s.%s, connected to net '%s', has negative "
                            "timing budget of %fns\n",
                            user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                            ctx->getDelayNS(user.budget));
            if (ctx->verbose)
                log_info("port %s.%s, connected to net '%s', has "
                         "timing budget of %fns\n",
                         user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                         ctx->getDelayNS(user.budget));
        }
    }

    log_info("Checksum: 0x%08x\n", ctx->checksum());
}

void update_budget(Context *ctx)
{
    UpdateMap updates;
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    delay_t min_slack = compute_min_slack(ctx, &updates, nullptr);

    // If user has not specified a frequency, adjust the frequency dynamically:
    if (!ctx->user_freq) {
        ctx->target_freq = 1e12 / (default_slack - min_slack);
        if (ctx->verbose)
            log_info("minimum slack for this update = %d, target Fmax for next update = %.2f MHz\n", min_slack,
                     ctx->target_freq / 1e6);
    }

    // Update the budgets
    for (auto &net : ctx->nets) {
        for (size_t i = 0; i < net.second->users.size(); ++i) {
            auto &user = net.second->users[i];
            auto pi = &user.cell->ports.at(user.port);
            auto it = updates.find(pi);
            if (it == updates.end())
                continue;
            user.budget = ctx->getNetinfoRouteDelay(net.second.get(), i) - it->second;

            // Post-update check
            if (ctx->verbose) {
                if (ctx->user_freq && user.budget < 0)
                    log_warning("port %s.%s, connected to net '%s', has negative "
                                "timing budget of %fns\n",
                                user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                                ctx->getDelayNS(user.budget));
                else
                    log_info("port %s.%s, connected to net '%s', has "
                             "timing budget of %fns\n",
                             user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx),
                             ctx->getDelayNS(user.budget));
            }
        }
    }
}

void compute_fmax(Context *ctx, bool print_fmax, bool print_path)
{
    delay_t default_slack = delay_t(1.0e12 / ctx->target_freq);
    PortRefList crit_path;
    delay_t min_slack = compute_min_slack(ctx, nullptr, &crit_path);
    if (print_path) {
        delay_t total = 0;
        log_break();
        log_info("Critical path report:\n");
        log_info("curr total\n");
        auto &front = crit_path.front();
        auto &front_port = front->cell->ports.at(front->port);
        auto &front_driver = front_port.net->driver;
        auto last_port = ctx->getPortClock(front_driver.cell, front_driver.port);
        for (auto sink : crit_path) {
            auto sink_cell = sink->cell;
            auto &port = sink_cell->ports.at(sink->port);
            auto net = port.net;
            unsigned i = 0;
            for (auto &usr : net->users)
                if (&usr == sink) break;
                else ++i;
            auto &driver = net->driver;
            auto driver_cell = driver.cell;
            delay_t comb_delay;
            ctx->getCellDelay(sink_cell, last_port, driver.port, comb_delay);
            total += comb_delay;
            log_info("%4d %4d  Source %s.%s\n", comb_delay, total, driver_cell->name.c_str(ctx),
                     driver.port.c_str(ctx));
            delay_t net_delay = ctx->getNetinfoRouteDelay(net, i);
            total += net_delay;
            auto driver_loc = ctx->getBelLocation(driver_cell->bel);
            auto sink_loc = ctx->getBelLocation(sink_cell->bel);
            log_info("%4d %4d    Net %s budget %d (%d,%d) -> (%d,%d)\n", net_delay, total, net->name.c_str(ctx),
                     sink->budget, driver_loc.x, driver_loc.y, sink_loc.x, sink_loc.y);
            log_info("                Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx));
            last_port = sink->port;
        }
        log_break();
    }
    if (print_fmax)
        log_info("estimated Fmax = %.2f MHz\n", 1e6 / (default_slack - min_slack));
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <TinyCLR.h>
#include <Device.h>

#define EXPAND(a) CONCAT(DEVICE_TARGET, a)

void OnSoftReset(const TinyCLR_Api_Provider* apiProvider) {
#ifdef INCLUDE_ADC
    apiProvider->Add(apiProvider, EXPAND(_Adc_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::AdcProvider, EXPAND(_Adc_GetApi)()->Name);

    EXPAND(_Adc_Reset)();
#endif

#ifdef INCLUDE_DAC
    apiProvider->Add(apiProvider, EXPAND(_Dac_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::DacProvider, EXPAND(_Dac_GetApi)()->Name);

    EXPAND(_Dac_Reset)();
#endif

#ifdef INCLUDE_DISPLAY
    apiProvider->Add(apiProvider, EXPAND(_Display_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::DisplayProvider, EXPAND(_Display_GetApi)()->Name);

    EXPAND(_Display_Reset)();
#endif

#ifdef INCLUDE_GPIO
    apiProvider->Add(apiProvider, EXPAND(_Gpio_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::GpioProvider, EXPAND(_Gpio_GetApi)()->Name);

    EXPAND(_Gpio_Reset)();
#endif

#ifdef INCLUDE_I2C
    apiProvider->Add(apiProvider, EXPAND(_I2c_GetApi)());

    EXPAND(_I2c_Reset)();
#endif

#ifdef INCLUDE_PWM
    apiProvider->Add(apiProvider, EXPAND(_Pwm_GetApi)());

    EXPAND(_Pwm_Reset)();
#endif

#ifdef INCLUDE_SPI
    apiProvider->Add(apiProvider, EXPAND(_Spi_GetApi)());

    EXPAND(_Spi_Reset)();
#endif

#ifdef INCLUDE_UART
    apiProvider->Add(apiProvider, EXPAND(_Uart_GetApi)());

    EXPAND(_Uart_Reset)();
#endif

#ifdef INCLUDE_USBCLIENT
    apiProvider->Add(apiProvider, EXPAND(_UsbClient_GetApi)());

    EXPAND(_UsbClient_Reset)();
#endif
}

int main() {
    EXPAND(_Startup_Initialize)();

    uint8_t* heapStart;
    size_t heapLength;

    EXPAND(_Startup_GetHeap)(heapStart, heapLength);
    TinyCLR_Startup_AddHeapRegion(heapStart, heapLength);

    const TinyCLR_Api_Info* debuggerApi;
    size_t debuggerIndex;

    EXPAND(_Startup_GetDebugger)(debuggerApi, debuggerIndex);
    TinyCLR_Startup_SetDebugger(debuggerApi, debuggerIndex);

    TinyCLR_Startup_SetDeviceInformation(DEVICE_NAME, DEVICE_MANUFACTURER, DEVICE_VERSION);

    TinyCLR_Startup_SetRequiredProviders(EXPAND(_Deployment_GetApi)(), EXPAND(_Interrupt_GetApi)(), EXPAND(_Power_GetApi)(), EXPAND(_Time_GetApi)());

    auto runApp = true;

    EXPAND(_Startup_GetRunApp)(runApp);
    TinyCLR_Startup_Start(&OnSoftReset, runApp);

    return 0;
}
<commit_msg>Renamed macro.<commit_after>// Copyright GHI Electronics, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <TinyCLR.h>
#include <Device.h>

#define TARGET(a) CONCAT(DEVICE_TARGET, a)

void OnSoftReset(const TinyCLR_Api_Provider* apiProvider) {
#ifdef INCLUDE_ADC
    apiProvider->Add(apiProvider, TARGET(_Adc_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::AdcProvider, TARGET(_Adc_GetApi)()->Name);

    TARGET(_Adc_Reset)();
#endif

#ifdef INCLUDE_DAC
    apiProvider->Add(apiProvider, TARGET(_Dac_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::DacProvider, TARGET(_Dac_GetApi)()->Name);

    TARGET(_Dac_Reset)();
#endif

#ifdef INCLUDE_DISPLAY
    apiProvider->Add(apiProvider, TARGET(_Display_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::DisplayProvider, TARGET(_Display_GetApi)()->Name);

    TARGET(_Display_Reset)();
#endif

#ifdef INCLUDE_GPIO
    apiProvider->Add(apiProvider, TARGET(_Gpio_GetApi)());
    apiProvider->SetDefaultSelector(apiProvider, TinyCLR_Api_Type::GpioProvider, TARGET(_Gpio_GetApi)()->Name);

    TARGET(_Gpio_Reset)();
#endif

#ifdef INCLUDE_I2C
    apiProvider->Add(apiProvider, TARGET(_I2c_GetApi)());

    TARGET(_I2c_Reset)();
#endif

#ifdef INCLUDE_PWM
    apiProvider->Add(apiProvider, TARGET(_Pwm_GetApi)());

    TARGET(_Pwm_Reset)();
#endif

#ifdef INCLUDE_SPI
    apiProvider->Add(apiProvider, TARGET(_Spi_GetApi)());

    TARGET(_Spi_Reset)();
#endif

#ifdef INCLUDE_UART
    apiProvider->Add(apiProvider, TARGET(_Uart_GetApi)());

    TARGET(_Uart_Reset)();
#endif

#ifdef INCLUDE_USBCLIENT
    apiProvider->Add(apiProvider, TARGET(_UsbClient_GetApi)());

    TARGET(_UsbClient_Reset)();
#endif
}

int main() {
    TARGET(_Startup_Initialize)();

    uint8_t* heapStart;
    size_t heapLength;

    TARGET(_Startup_GetHeap)(heapStart, heapLength);
    TinyCLR_Startup_AddHeapRegion(heapStart, heapLength);

    const TinyCLR_Api_Info* debuggerApi;
    size_t debuggerIndex;

    TARGET(_Startup_GetDebugger)(debuggerApi, debuggerIndex);
    TinyCLR_Startup_SetDebugger(debuggerApi, debuggerIndex);

    TinyCLR_Startup_SetDeviceInformation(DEVICE_NAME, DEVICE_MANUFACTURER, DEVICE_VERSION);

    TinyCLR_Startup_SetRequiredProviders(TARGET(_Deployment_GetApi)(), TARGET(_Interrupt_GetApi)(), TARGET(_Power_GetApi)(), TARGET(_Time_GetApi)());

    auto runApp = true;

    TARGET(_Startup_GetRunApp)(runApp);
    TinyCLR_Startup_Start(&OnSoftReset, runApp);

    return 0;
}
<|endoftext|>


<commit_before>#include "MainFrame.h"
#include <algorithm>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/button.h>
#include "ImageViewPanel.h"
#include "ZipEntry.h"
#include "FileEntry.h"

enum MainFrameIds { ID_DIRECTORY_TREE = 1, ID_IMAGE_BUTTON };

MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, "ZipPicView") {
  auto statusBar = CreateStatusBar();
  SetStatusText("Welcome to ZipPicView!");

  auto outerSizer = new wxBoxSizer(wxVERTICAL);
  auto toolSizer = new wxBoxSizer(wxHORIZONTAL);
  onTopChk = new wxCheckBox(this, wxID_ANY, "On Top");
  onTopChk->Bind(wxEVT_CHECKBOX, &MainFrame::OnOnTopChecked, this);
  notebook = new wxNotebook(this, wxID_ANY);

  currentFileCtrl =
      new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                     wxDefaultSize, wxTE_READONLY);

  dirBrowseBtn = new wxButton(this, wxID_ANY, "Directory...");
  dirBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnDirBrowsePressed, this);
  zipBrowseBtn = new wxButton(this, wxID_ANY, "Zip...");
  zipBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnZipBrowsePressed, this);

  toolSizer->Add(currentFileCtrl, 1, wxEXPAND);
  toolSizer->Add(dirBrowseBtn, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);
  toolSizer->Add(zipBrowseBtn, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);
  toolSizer->Add(onTopChk, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);

  progress = new wxGauge(this, wxID_ANY, 100);

  outerSizer->Add(toolSizer, 0, wxEXPAND | wxALL, 5);
  outerSizer->Add(notebook, 1, wxEXPAND | wxALL, 5);
  outerSizer->Add(progress, 0);

  splitter = new wxSplitterWindow(notebook, wxID_ANY);
  splitter->Bind(wxEVT_SPLITTER_DOUBLECLICKED,
                 [](wxSplitterEvent &event) { event.Veto(); }, wxID_ANY);
  dirTree =
      new wxTreeCtrl(splitter, ID_DIRECTORY_TREE, wxDefaultPosition,
                     wxDefaultSize, wxTR_SINGLE | wxTR_FULL_ROW_HIGHLIGHT);
  dirTree->Bind(wxEVT_TREE_SEL_CHANGED, &MainFrame::OnTreeSelectionChanged,
                this, ID_DIRECTORY_TREE);
  dirTree->Bind(wxEVT_TREE_ITEM_COLLAPSING,
                [=](wxTreeEvent &event) { event.Veto(); }, ID_DIRECTORY_TREE);
  dirTree->SetMinSize({250, 250});

  auto rightWindow = new wxScrolledWindow(splitter, wxID_ANY);
  auto grid = new wxGridSizer(5);
  rightWindow->SetSizer(grid);
  rightWindow->SetScrollRate(10, 10);
  rightWindow->SetMinSize({250, 250});
  rightWindow->Bind(wxEVT_SIZE, &MainFrame::OnGridPanelSize, this);
  splitter->SplitVertically(dirTree, rightWindow, 250);

  notebook->AddPage(splitter, "Browse");

  Bind(wxEVT_COMMAND_THMBTREAD_UPDATE, OnThumbnailLoadUpdated, this);
  Bind(wxEVT_COMMAND_THMBTREAD_DONE, OnThumbnailLoadDone, this);

  SetSizer(outerSizer);
  SetMinSize({640, 480});
  SetSize({640, 480});
}

void MainFrame::BuildDirectoryTree() {
  auto root = dirTree->AddRoot(entry->Name(), -1, -1, new EntryItemData(entry));
  AddTreeItemsFromEntry(root, entry);
}

void MainFrame::AddTreeItemsFromEntry(const wxTreeItemId &itemId,
                                      Entry *entry) {
  for (auto childEntry : *entry) {
    if (!childEntry->IsDirectory())
      return;

    auto child = dirTree->AppendItem(itemId, childEntry->Name(), -1, -1,
                                     new EntryItemData(childEntry));

    AddTreeItemsFromEntry(child, childEntry);
  }
}

void MainFrame::OnTreeSelectionChanged(wxTreeEvent &event) {
  auto treeItemId = event.GetItem();
  auto rootId = dirTree->GetRootItem();
  auto currentFileEntry =
      dynamic_cast<EntryItemData *>(dirTree->GetItemData(treeItemId))->Get();

  auto gridPanel = dynamic_cast<wxScrolledWindow *>(splitter->GetWindow2());
  gridPanel->Show(false);
  auto grid = gridPanel->GetSizer();
  grid->Clear(true);

  std::vector<Entry *> loadEntries;
  imgButtons.clear();
  for (int i = 0; i < currentFileEntry->Count(); ++i) {
    Entry *childEntry = (*currentFileEntry)[i];

    if (childEntry->IsDirectory())
      continue;
    loadEntries.push_back(childEntry);
    auto ext = childEntry->Name().AfterLast('.').Lower();

    if (ext != "jpg" && ext != "jpeg" && ext != "png" && ext != "gif")
      continue;
    auto button = new wxButton(gridPanel, wxID_ANY);
    imgButtons.push_back(button);
    button->Bind(wxEVT_BUTTON, &MainFrame::OnImageButtonClick, this);

    button->SetClientObject(new EntryItemData(childEntry));
    button->SetMinSize({250, 250});

    auto staticText = new wxStaticText(gridPanel, wxID_ANY, childEntry->Name());
    staticText->SetMaxSize({250, 50});

    auto btnSizer = new wxBoxSizer(wxVERTICAL);
    btnSizer->Add(button, 0, wxEXPAND);
    btnSizer->Add(staticText);

    grid->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
  }

  if (loadThread) {
    loadThread->Delete();
    delete loadThread;
    loadThread = nullptr;
  }

  loadThread = new ThumbnailLoadThread(this, loadEntries);
  loadThread->Run();

  progress->SetRange(loadEntries.size());
  grid->FitInside(gridPanel);
  gridPanel->Show(true);
  gridPanel->Scroll(0, 0);

  gridPanel->Refresh();
  gridPanel->Update();
}

void MainFrame::OnImageButtonClick(wxCommandEvent &event) {
  auto button = dynamic_cast<wxButton *>(event.GetEventObject());
  auto clientData =
      dynamic_cast<wxStringClientData *>(button->GetClientObject());

  auto page = notebook->GetPageCount();
  auto childEntry =
      dynamic_cast<EntryItemData *>(button->GetClientObject())->Get();
  auto bitmapCtl = new ImageViewPanel(notebook, childEntry->LoadImage());
  notebook->AddPage(bitmapCtl, childEntry->Name());
  notebook->SetSelection(page);
}

void MainFrame::OnGridPanelSize(wxSizeEvent &event) {
  auto grid = dynamic_cast<wxGridSizer *>(splitter->GetWindow2()->GetSizer());
  auto size = event.GetSize();
  int col = (size.GetWidth() / 250);
  grid->SetCols(col > 0 ? col : 1);

  grid->FitInside(splitter->GetWindow2());
  splitter->Refresh();
  splitter->Update();
}

void MainFrame::OnOnTopChecked(wxCommandEvent &event) {
  auto style = GetWindowStyle();

  if (onTopChk->IsChecked()) {
    style += wxSTAY_ON_TOP;
  } else {
    style -= wxSTAY_ON_TOP;
  }
  SetWindowStyle(style);
}

void MainFrame::OnDirBrowsePressed(wxCommandEvent &event) {
  wxDirDialog dlg(NULL, "Choose directory", "",
                  wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
  if (dlg.ShowModal() == wxID_CANCEL)
    return;
  auto oldEntry = entry;

  wxFileName filename = wxFileName::DirName(dlg.GetPath());
  auto entry = FileEntry::Create(filename);
  SetEntry(entry);
  currentFileCtrl->SetValue(filename.GetFullPath());
}

void MainFrame::OnZipBrowsePressed(wxCommandEvent &event) {
  wxFileDialog dialog(this, _("Open ZIP file"), "", "",
                      "ZIP files (*.zip)|*.zip",
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (dialog.ShowModal() == wxID_CANCEL)
    return;

  auto path = dialog.GetPath();
  wxFileName filename(path);

  auto entry = ZipEntry::Create(path);
  SetEntry(entry);
  currentFileCtrl->SetValue(filename.GetFullPath());
}

void MainFrame::SetEntry(Entry *entry) {
  auto oldEntry = MainFrame::entry;
  MainFrame::entry = entry;

  dirTree->DeleteAllItems();

  BuildDirectoryTree();

  dirTree->ExpandAll();
  dirTree->UnselectAll();
  dirTree->SelectItem(dirTree->GetRootItem());

  if (oldEntry) {
    delete oldEntry;
  }
}

void MainFrame::OnThumbnailLoadUpdated(wxThreadEvent &event) {
  auto data = event.GetPayload<ThumbnailData>();
  progress->SetValue(data.index);
  imgButtons[data.index]->SetBitmap(data.image);
}

void MainFrame::OnThumbnailLoadDone(wxThreadEvent &event) {
  progress->SetValue(progress->GetRange());
}
<commit_msg>Fix: Prevent thread double deletion that cause SEGFAULT.<commit_after>#include "MainFrame.h"
#include <algorithm>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/button.h>
#include "ImageViewPanel.h"
#include "ZipEntry.h"
#include "FileEntry.h"

enum MainFrameIds { ID_DIRECTORY_TREE = 1, ID_IMAGE_BUTTON };

MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, "ZipPicView") {
  auto statusBar = CreateStatusBar();
  SetStatusText("Welcome to ZipPicView!");

  auto outerSizer = new wxBoxSizer(wxVERTICAL);
  auto toolSizer = new wxBoxSizer(wxHORIZONTAL);
  onTopChk = new wxCheckBox(this, wxID_ANY, "On Top");
  onTopChk->Bind(wxEVT_CHECKBOX, &MainFrame::OnOnTopChecked, this);
  notebook = new wxNotebook(this, wxID_ANY);

  currentFileCtrl =
      new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
                     wxDefaultSize, wxTE_READONLY);

  dirBrowseBtn = new wxButton(this, wxID_ANY, "Directory...");
  dirBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnDirBrowsePressed, this);
  zipBrowseBtn = new wxButton(this, wxID_ANY, "Zip...");
  zipBrowseBtn->Bind(wxEVT_BUTTON, &MainFrame::OnZipBrowsePressed, this);

  toolSizer->Add(currentFileCtrl, 1, wxEXPAND);
  toolSizer->Add(dirBrowseBtn, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);
  toolSizer->Add(zipBrowseBtn, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);
  toolSizer->Add(onTopChk, 0, wxEXPAND | wxLEFT | wxALIGN_BOTTOM, 5);

  progress = new wxGauge(this, wxID_ANY, 100);

  outerSizer->Add(toolSizer, 0, wxEXPAND | wxALL, 5);
  outerSizer->Add(notebook, 1, wxEXPAND | wxALL, 5);
  outerSizer->Add(progress, 0);

  splitter = new wxSplitterWindow(notebook, wxID_ANY);
  splitter->Bind(wxEVT_SPLITTER_DOUBLECLICKED,
                 [](wxSplitterEvent &event) { event.Veto(); }, wxID_ANY);
  dirTree =
      new wxTreeCtrl(splitter, ID_DIRECTORY_TREE, wxDefaultPosition,
                     wxDefaultSize, wxTR_SINGLE | wxTR_FULL_ROW_HIGHLIGHT);
  dirTree->Bind(wxEVT_TREE_SEL_CHANGED, &MainFrame::OnTreeSelectionChanged,
                this, ID_DIRECTORY_TREE);
  dirTree->Bind(wxEVT_TREE_ITEM_COLLAPSING,
                [=](wxTreeEvent &event) { event.Veto(); }, ID_DIRECTORY_TREE);
  dirTree->SetMinSize({250, 250});

  auto rightWindow = new wxScrolledWindow(splitter, wxID_ANY);
  auto grid = new wxGridSizer(5);
  rightWindow->SetSizer(grid);
  rightWindow->SetScrollRate(10, 10);
  rightWindow->SetMinSize({250, 250});
  rightWindow->Bind(wxEVT_SIZE, &MainFrame::OnGridPanelSize, this);
  splitter->SplitVertically(dirTree, rightWindow, 250);

  notebook->AddPage(splitter, "Browse");

  Bind(wxEVT_COMMAND_THMBTREAD_UPDATE, &MainFrame::OnThumbnailLoadUpdated, this);
  Bind(wxEVT_COMMAND_THMBTREAD_DONE, &MainFrame::OnThumbnailLoadDone, this);

  SetSizer(outerSizer);
  SetMinSize({640, 480});
  SetSize({640, 480});
}

void MainFrame::BuildDirectoryTree() {
  auto root = dirTree->AddRoot(entry->Name(), -1, -1, new EntryItemData(entry));
  AddTreeItemsFromEntry(root, entry);
}

void MainFrame::AddTreeItemsFromEntry(const wxTreeItemId &itemId,
                                      Entry *entry) {
  for (auto childEntry : *entry) {
    if (!childEntry->IsDirectory())
      return;

    auto child = dirTree->AppendItem(itemId, childEntry->Name(), -1, -1,
                                     new EntryItemData(childEntry));

    AddTreeItemsFromEntry(child, childEntry);
  }
}

void MainFrame::OnTreeSelectionChanged(wxTreeEvent &event) {
  auto treeItemId = event.GetItem();
  auto rootId = dirTree->GetRootItem();
  auto currentFileEntry =
      dynamic_cast<EntryItemData *>(dirTree->GetItemData(treeItemId))->Get();

  auto gridPanel = dynamic_cast<wxScrolledWindow *>(splitter->GetWindow2());
  gridPanel->Show(false);
  auto grid = gridPanel->GetSizer();
  grid->Clear(true);

  std::vector<Entry *> loadEntries;
  imgButtons.clear();
  for (int i = 0; i < currentFileEntry->Count(); ++i) {
    Entry *childEntry = (*currentFileEntry)[i];

    if (childEntry->IsDirectory())
      continue;
    auto ext = childEntry->Name().AfterLast('.').Lower();

    if (ext != "jpg" && ext != "jpeg" && ext != "png" && ext != "gif")
      continue;

    loadEntries.push_back(childEntry);
    auto button = new wxButton(gridPanel, wxID_ANY);
    imgButtons.push_back(button);
    button->Bind(wxEVT_BUTTON, &MainFrame::OnImageButtonClick, this);

    button->SetClientObject(new EntryItemData(childEntry));
    button->SetMinSize({250, 250});

    auto staticText = new wxStaticText(gridPanel, wxID_ANY, childEntry->Name());
    staticText->SetMaxSize({250, 50});

    auto btnSizer = new wxBoxSizer(wxVERTICAL);
    btnSizer->Add(button, 0, wxEXPAND);
    btnSizer->Add(staticText);

    grid->Add(btnSizer, 0, wxALL | wxEXPAND, 5);
  }

  progress->SetRange(loadEntries.size());

  if (loadThread) {
    loadThread->Delete(nullptr, wxTHREAD_WAIT_BLOCK);
    loadThread = nullptr;
  }

  loadThread = new ThumbnailLoadThread(this, loadEntries);
  loadThread->Run();

  grid->FitInside(gridPanel);
  gridPanel->Show(true);
  gridPanel->Scroll(0, 0);

  gridPanel->Refresh();
  gridPanel->Update();
}

void MainFrame::OnImageButtonClick(wxCommandEvent &event) {
  auto button = dynamic_cast<wxButton *>(event.GetEventObject());
  auto clientData =
      dynamic_cast<wxStringClientData *>(button->GetClientObject());

  auto page = notebook->GetPageCount();
  auto childEntry =
      dynamic_cast<EntryItemData *>(button->GetClientObject())->Get();
  auto bitmapCtl = new ImageViewPanel(notebook, childEntry->LoadImage());
  notebook->AddPage(bitmapCtl, childEntry->Name());
  notebook->SetSelection(page);
}

void MainFrame::OnGridPanelSize(wxSizeEvent &event) {
  auto grid = dynamic_cast<wxGridSizer *>(splitter->GetWindow2()->GetSizer());
  auto size = event.GetSize();
  int col = (size.GetWidth() / 250);
  grid->SetCols(col > 0 ? col : 1);

  grid->FitInside(splitter->GetWindow2());
  splitter->Refresh();
  splitter->Update();
}

void MainFrame::OnOnTopChecked(wxCommandEvent &event) {
  auto style = GetWindowStyle();

  if (onTopChk->IsChecked()) {
    style += wxSTAY_ON_TOP;
  } else {
    style -= wxSTAY_ON_TOP;
  }
  SetWindowStyle(style);
}

void MainFrame::OnDirBrowsePressed(wxCommandEvent &event) {
  wxDirDialog dlg(NULL, "Choose directory", "",
                  wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
  if (dlg.ShowModal() == wxID_CANCEL)
    return;
  auto oldEntry = entry;

  wxFileName filename = wxFileName::DirName(dlg.GetPath());
  auto entry = FileEntry::Create(filename);
  SetEntry(entry);
  currentFileCtrl->SetValue(filename.GetFullPath());
}

void MainFrame::OnZipBrowsePressed(wxCommandEvent &event) {
  wxFileDialog dialog(this, _("Open ZIP file"), "", "",
                      "ZIP files (*.zip)|*.zip",
                      wxFD_OPEN | wxFD_FILE_MUST_EXIST);
  if (dialog.ShowModal() == wxID_CANCEL)
    return;

  auto path = dialog.GetPath();
  wxFileName filename(path);

  auto entry = ZipEntry::Create(path);
  SetEntry(entry);
  currentFileCtrl->SetValue(filename.GetFullPath());
}

void MainFrame::SetEntry(Entry *entry) {
  auto oldEntry = MainFrame::entry;
  MainFrame::entry = entry;

  dirTree->DeleteAllItems();

  BuildDirectoryTree();

  dirTree->ExpandAll();
  dirTree->UnselectAll();
  dirTree->SelectItem(dirTree->GetRootItem());

  if (oldEntry) {
    delete oldEntry;
  }
}

void MainFrame::OnThumbnailLoadUpdated(wxThreadEvent &event) {
  auto data = event.GetPayload<ThumbnailData>();
  if(data.index > progress->GetRange()) return;

  progress->SetValue(data.index);
  imgButtons[data.index]->SetBitmap(data.image);
}

void MainFrame::OnThumbnailLoadDone(wxThreadEvent &event) {
  progress->SetValue(progress->GetRange());
  loadThread = nullptr;
}
<|endoftext|>