<commit_before>// SimpleLayout.cpp

#include "SimpleLayout.h"
#include "SimpleLayoutData.h"
#include "SimpleTextRunLoop.h"
#include "SimpleTextBlock.h"
#include "TextLayoutArgs.h"
#include "TextDocument.h"
#include "TextStyleRegistry.h"
#include "Assert.h"
#include <algorithm>

#undef min
#undef max

class DebuggableException {};
class SimpleLayoutFailed : public DebuggableException {};

static size_t LayoutRun( SimpleTextRun run,
                         SimpleLayoutData& layoutData,
                         const TextLayoutArgs& args,
                         int xStart,
                         bool forceFit )
{
	SIZE size;
	INT fit;

	int maxWidth = ( forceFit || args.maxWidth == 0 ) ? std::numeric_limits<int>::max() : args.maxWidth;

	if ( run.textCount == 1 && args.text[run.textStart] == '\t' && args.styleRegistry.tabSize > 0 )
	{
		int tabWidth = args.styleRegistry.tabSize - ( xStart % args.styleRegistry.tabSize );
		layoutData.xOffsets[run.textStart - 1] = tabWidth;
		fit = ( tabWidth < maxWidth ? 1 : 0 );
	}
	else
	{
		size_t textCount = std::min<size_t>( run.textCount, 256 );

		SelectObject( args.hdc, args.styleRegistry.Font( run.fontid ).hfont );
		if ( !GetTextExtentExPoint( args.hdc,
		                            args.text.begin() + run.textStart,
		                            textCount,
		                            args.maxWidth - std::min( maxWidth, xStart ),
		                            &fit,
		                            &layoutData.xOffsets.front() + run.textStart,
		                            &size ) )
		{
			Assert( false );
			throw SimpleLayoutFailed();
		}
	}

	run.textCount = fit;
	layoutData.runs.push_back( run );
	return fit;
}

static size_t WrapLine( SimpleLayoutData& layoutData,
                        const TextLayoutArgs& args,
                        size_t lineStart,
                        int lineWidth )
{
	SimpleTextRun lastRun = layoutData.runs.back();

	// 'lastRun' can have a textCount of 0
	size_t estimate = args.textStart + lastRun.textStart + lastRun.textCount;

	size_t lineEnd = args.doc.PrevSoftBreak( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = args.doc.PrevWordStop( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = args.doc.PrevCharStop( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = estimate;

	lineEnd -= args.textStart;

	layoutData.DiscardFrom( lineEnd );

	if ( lineStart == lineEnd )
	{
		lastRun.textCount = 1;
		LayoutRun( lastRun, layoutData, args, lineWidth, true );
		lineEnd++;
	}

	return lineEnd;
}

TextBlockPtr SimpleLayoutParagraph( const TextLayoutArgs& args )
{
	SimpleLayoutDataPtr layoutData( new SimpleLayoutData( args.text, args.endsWithNewline ) );

	int    lineWidth = 0;
	size_t lineStart = 0;

	for ( SimpleTextRunLoop loop( args.text, args.fonts ); loop.Unfinished(); )
	{
		SimpleTextRun run = loop.NextRun();
		size_t fit = LayoutRun( run, *layoutData, args, lineWidth, false );

		if ( fit == run.textCount )
		{
			lineWidth += layoutData->xOffsets[run.textStart + run.textCount];
		}
		else
		{
			lineStart = WrapLine( *layoutData, args, lineStart, lineWidth );
			lineWidth = 0;

			layoutData->lines.push_back( layoutData->runs.size() );
			loop.NewLine( lineStart );
		}
	}

	if ( layoutData->lines.empty() || layoutData->lines.back() != layoutData->runs.size() )
		layoutData->lines.push_back( layoutData->runs.size() );

	return TextBlockPtr( new SimpleTextBlock( std::move( layoutData ), args.styleRegistry ) );
}
<commit_msg>Fix a maxSize bug, and an array indexing bug introduced by the last change.<commit_after>// SimpleLayout.cpp

#include "SimpleLayout.h"
#include "SimpleLayoutData.h"
#include "SimpleTextRunLoop.h"
#include "SimpleTextBlock.h"
#include "TextLayoutArgs.h"
#include "TextDocument.h"
#include "TextStyleRegistry.h"
#include "Assert.h"
#include <algorithm>

#undef min
#undef max

class DebuggableException {};
class SimpleLayoutFailed : public DebuggableException {};

static size_t LayoutRun( SimpleTextRun run,
                         SimpleLayoutData& layoutData,
                         const TextLayoutArgs& args,
                         int xStart,
                         bool forceFit )
{
	SIZE size;
	INT fit;

	int maxWidth = ( forceFit || args.maxWidth == 0 ) ? std::numeric_limits<int>::max() : args.maxWidth;

	if ( run.textCount == 1 && args.text[run.textStart] == '\t' && args.styleRegistry.tabSize > 0 )
	{
		int tabWidth = args.styleRegistry.tabSize - ( xStart % args.styleRegistry.tabSize );
		layoutData.xOffsets[run.textStart] = tabWidth;
		fit = ( tabWidth < maxWidth ? 1 : 0 );
	}
	else
	{
		size_t textCount = std::min<size_t>( run.textCount, 256 );

		SelectObject( args.hdc, args.styleRegistry.Font( run.fontid ).hfont );
		if ( !GetTextExtentExPoint( args.hdc,
		                            args.text.begin() + run.textStart,
		                            textCount,
		                            maxWidth - std::min( maxWidth, xStart ),
		                            &fit,
		                            &layoutData.xOffsets.front() + run.textStart,
		                            &size ) )
		{
			Assert( false );
			throw SimpleLayoutFailed();
		}
	}

	run.textCount = fit;
	layoutData.runs.push_back( run );
	return fit;
}

static size_t WrapLine( SimpleLayoutData& layoutData,
                        const TextLayoutArgs& args,
                        size_t lineStart,
                        int lineWidth )
{
	SimpleTextRun lastRun = layoutData.runs.back();

	// 'lastRun' can have a textCount of 0
	size_t estimate = args.textStart + lastRun.textStart + lastRun.textCount;

	size_t lineEnd = args.doc.PrevSoftBreak( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = args.doc.PrevWordStop( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = args.doc.PrevCharStop( estimate + 1 );

	if ( lineEnd <= args.textStart + lineStart )
		lineEnd = estimate;

	lineEnd -= args.textStart;

	layoutData.DiscardFrom( lineEnd );

	if ( lineStart == lineEnd )
	{
		lastRun.textCount = 1;
		LayoutRun( lastRun, layoutData, args, lineWidth, true );
		lineEnd++;
	}

	return lineEnd;
}

TextBlockPtr SimpleLayoutParagraph( const TextLayoutArgs& args )
{
	SimpleLayoutDataPtr layoutData( new SimpleLayoutData( args.text, args.endsWithNewline ) );

	int    lineWidth = 0;
	size_t lineStart = 0;

	for ( SimpleTextRunLoop loop( args.text, args.fonts ); loop.Unfinished(); )
	{
		SimpleTextRun run = loop.NextRun();
		size_t fit = LayoutRun( run, *layoutData, args, lineWidth, false );

		if ( fit == run.textCount )
		{
			lineWidth += layoutData->xOffsets[run.textStart + run.textCount - 1];
		}
		else
		{
			lineStart = WrapLine( *layoutData, args, lineStart, lineWidth );
			lineWidth = 0;

			layoutData->lines.push_back( layoutData->runs.size() );
			loop.NewLine( lineStart );
		}
	}

	if ( layoutData->lines.empty() || layoutData->lines.back() != layoutData->runs.size() )
		layoutData->lines.push_back( layoutData->runs.size() );

	return TextBlockPtr( new SimpleTextBlock( std::move( layoutData ), args.styleRegistry ) );
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000000000000000;

typedef tuple<ll, ll, ll> state;

int main () {
  int N;
  cin >> N;
  ll a[200010];
  for (auto i = 0; i < N; ++i) {
    cin >> a[i];
  }
  priority_queue<state, vector<state>, greater<state> > Q;
  ll ans[200010];
  fill(ans, ans+200010, infty);
  for (auto i = 0; i < N; ++i) {
    Q.push(state(a[i], i, 0));
  }
  while(!Q.empty()) {
    ll num = get<0>(Q.top());
    ll place = get<1>(Q.top());
    ll dist = get<2>(Q.top());
    Q.pop();
    if (ans[place] == infty) {
      ans[place] = num;
      ll nplace[2] = {num + 1, num - 1};
      ll ndist = dist+1;
      ll nnum = num - dist * dist + ndist * ndist;
      for (auto j = 0; j < 2; ++j) {
        if (0 <= nplace[j] && nplace[j] < N) {
          Q.push(state(nnum, nplace[j], ndist));
        }
      }
    }
  }
  for (auto i = 0; i < N; ++i) {
    cout << a[i] << endl;
  }
}
<commit_msg>tried C.cpp to 'C'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000000000000000;

typedef tuple<ll, ll, ll> state;

int main () {
  int N;
  cin >> N;
  ll a[200010];
  for (auto i = 0; i < N; ++i) {
    cin >> a[i];
  }
  priority_queue<state, vector<state>, greater<state> > Q;
  ll ans[200010];
  fill(ans, ans+200010, infty);
  for (auto i = 0; i < N; ++i) {
    Q.push(state(a[i], i, 0));
  }
  while(!Q.empty()) {
    ll num = get<0>(Q.top());
    ll place = get<1>(Q.top());
    ll dist = get<2>(Q.top());
    Q.pop();
    if (ans[place] == infty) {
      ans[place] = num;
      ll nplace[2] = {place + 1, place - 1};
      ll ndist = dist+1;
      ll nnum = num - dist * dist + ndist * ndist;
      for (auto j = 0; j < 2; ++j) {
        if (0 <= nplace[j] && nplace[j] < N) {
          Q.push(state(nnum, nplace[j], ndist));
        }
      }
    }
  }
  for (auto i = 0; i < N; ++i) {
    cout << a[i] << endl;
  }
}
<|endoftext|>


<commit_before>/**
 * File    : D.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-4-7 15:32:10
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const int infty = 1000000007;

int N, M, L, X;
int a[1010];
int DP[1010];
int DP2[1010];
int sum;

int main()
{
  cin >> N >> M >> L >> X;
  for (auto i = 0; i < N; i++)
  {
    cin >> a[i];
  }
  int maxi = (X - 1) * M + L;
  fill(DP, DP + M, infty);
  DP[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < M; j++)
    {
      DP2[j] = DP[j];
    }
    for (auto j = 0; j < M; j++)
    {
      if (DP[j] == infty)
        continue;
      sum = DP[j] + a[i];
      DP2[sum % M] = min(DP[sum % M], sum);
    }
    for (auto j = 0; j < M; j++)
    {
      DP[j] = DP2[j];
    }
#if DEBUG == 1
    for (auto j = 0; j < M; j++)
    {
      cerr << DP[j] << " ";
    }
    cerr << endl;
#endif
  }
  cout << ((DP[L] <= maxi) ? "Yes" : "No") << endl;
}<commit_msg>tried D.cpp to 'D'<commit_after>/**
 * File    : D.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-4-7 15:32:10
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 1 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const int infty = 1000000007;

int N, M, L, X;
int a[1010];
int DP[1010];
int DP2[1010];
int sum;

int main()
{
  cin >> N >> M >> L >> X;
  for (auto i = 0; i < N; i++)
  {
    cin >> a[i];
  }
  int maxi = (X - 1) * M + L;
  fill(DP, DP + M, infty);
  DP[0] = 0;
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < M; j++)
    {
      if (DP[j] == infty)
        continue;
      sum = DP[j] + a[i];
      DP2[sum % M] = min(DP[sum % M], sum);
    }
    for (auto j = 0; j < M; j++)
    {
      DP[j] = DP2[j];
    }
#if DEBUG == 1
    for (auto j = 0; j < M; j++)
    {
      cerr << DP[j] << " ";
    }
    cerr << endl;
#endif
  }
  cerr << ((DP[L] <= maxi) ? "Yes" : "No") << endl;
}<|endoftext|>


<commit_before>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef CONSTANTS_HPP_
#define CONSTANTS_HPP_

/** Default mass of bacteria */
const int DEFAULT_MASS = 5;

/** Minimum width of board */
const int MIN_WIDTH = 5;

/** Maximum width of board */
const int MAX_WIDTH = 500;

/** Minimum height of board */
const int MIN_HEIGHT = 5;

/** Maximum height of board */
const int MAX_HEIGHT = 500;

/** Indent between minimum and default width/height */
const int INDENT = 15;

#endif
<commit_msg>Remove constant INDENT<commit_after>/*
 * bacteria-core, core for cellular automaton
 * Copyright (C) 2016 Pavel Dolgov
 *
 * See the LICENSE file for terms of use.
 */

#ifndef CONSTANTS_HPP_
#define CONSTANTS_HPP_

/** Default mass of bacteria */
const int DEFAULT_MASS = 5;

/** Minimum width of board */
const int MIN_WIDTH = 5;

/** Maximum width of board */
const int MAX_WIDTH = 500;

/** Minimum height of board */
const int MIN_HEIGHT = 5;

/** Maximum height of board */
const int MAX_HEIGHT = 500;

#endif
<|endoftext|>


<commit_before>#define DEBUG 1

/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2/17/2019, 2:03:40 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(10101010));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll MOD = 1000000007;

ll N, K;
ll memo[100010];

ll power(int x)
{
  if (x < 0)
  {
    return 0;
  }
  assert(x < 100010);
  return memo[x];
}

ll DP[5010][5010];
ll DP2[5010][5010];

void init()
{
  memo[0] = 1;
  for (auto i = 1; i < 100010; i++)
  {
    memo[i] = memo[i - 1] * 2;
    memo[i] %= MOD;
  }
  for (auto i = 0; i < N; i++)
  {
    DP[0][i] = power(i - (K - 1));
  }
  DP2[0][0] = DP[0][0];
  for (auto i = 1; i < N; i++)
  {
    DP2[0][i] = DP2[0][i - 1] + DP[0][i];
    DP2[0][i] %= MOD;
  }
}

void flush()
{
#if DEBUG == 1
  if (N <= 10)
  {
    for (auto i = 0; i < N; i++)
    {
      for (auto j = 0; j < N; j++)
      {
        cerr << "DP[" << i << "][" << j << "] = " << DP[i][j] << endl;
      }
    }
  }
#endif
  ll ans = 0;
  for (auto i = 0; i < N; i++)
  {
    ans += DP[i][N - 1];
    ans %= MOD;
  }
  cout << ans << endl;
}

int main()
{
  cin >> N >> K;
  init();
  for (auto i = 1; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      DP[i][j] = 0;
      if (j > 0)
      {
        DP[i][j] += (DP2[i - 1][j - 1] * power(j - i - (K - 1))) % MOD;
      }
      DP[i][j] += (DP[i - 1][j] * power(j - i - (K - 2))) % MOD;
    }
    DP2[i][0] = DP[i][0];
    for (auto j = 1; j < N; j++)
    {
      DP2[i][j] = DP2[i][j - 1] + DP[i][j];
      DP2[i][j] %= MOD;
    }
  }
  flush();
}<commit_msg>tried E.cpp to 'E'<commit_after>#define DEBUG 1

/**
 * File    : E.cpp
 * Author  : Kazune Takahashi
 * Created : 2/17/2019, 2:03:40 PM
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(10101010));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll MOD = 1000000007;

ll N, K;
ll memo[100010];

ll power(int x)
{
  if (x < 0)
  {
    return 0;
  }
  assert(x < 100010);
  return memo[x];
}

ll DP[5010][5010];
ll DP2[5010][5010];

void init()
{
  memo[0] = 1;
  for (auto i = 1; i < 100010; i++)
  {
    memo[i] = memo[i - 1] * 2;
    memo[i] %= MOD;
  }
  for (auto i = 0; i < N; i++)
  {
    DP[0][i] = power(i - (K - 2));
  }
  DP2[0][0] = DP[0][0];
  for (auto i = 1; i < N; i++)
  {
    DP2[0][i] = DP2[0][i - 1] + DP[0][i];
    DP2[0][i] %= MOD;
  }
}

void flush()
{
#if DEBUG == 1
  if (N <= 10)
  {
    for (auto i = 0; i < N; i++)
    {
      for (auto j = 0; j < N; j++)
      {
        cerr << "DP[" << i << "][" << j << "] = " << DP[i][j] << endl;
      }
    }
  }
#endif
  cout << DP[N - 1][N - 1] << endl;
}

int main()
{
  cin >> N >> K;
  init();
  for (auto i = 1; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      DP[i][j] = 0;
      if (j > 0)
      {
        DP[i][j] += (DP2[i - 1][j - 1] * power(j - i - (K - 2))) % MOD;
      }
      DP[i][j] += (DP[i - 1][j] * power(j - i - (K - 1))) % MOD;
    }
    DP2[i][0] = DP[i][0];
    for (auto j = 1; j < N; j++)
    {
      DP2[i][j] = DP2[i][j - 1] + DP[i][j];
      DP2[i][j] %= MOD;
    }
  }
  flush();
}<|endoftext|>


<commit_before>#include "ledtable.h"

LEDTable::LEDTable(int pin,
    int width,
    int height,
    PixelOrder pixelorder,
    neoPixelType strip_type) : _width(width), _height(height), _pixelorder(pixelorder), strip_type(strip_type), pin(pin)
{
  /* determine whether the table is rotated by 90° */
  int x = originalWidth() - 1;
  int y = originalHeight() - 1;
  pixelOrder(&x, &y);
  _widthAndHeightAreSwitched = isOutsideTransformed(x, y);
  /* create the strip */
  strip = NULL;
#ifdef USE_SERIAL_CONNECTION
  printed_pixels = NULL;
#endif
}

LEDTable::~LEDTable()
{
  if (strip)
  {
    delete strip;
  }
#ifdef USE_SERIAL_CONNECTION
  free(printed_pixels);
#endif
}

void LEDTable::begin()
{
  if (!strip)
  {
    strip = new Adafruit_NeoPixel(this->originalWidth() * this->originalHeight(), pin, strip_type);
  }
  if (strip)
  {
    strip->begin();
  }
}

void LEDTable::show()
{
  if (strip)
  {
    strip->show();
  }
}

boolean LEDTable::canShow()
{
  return strip && strip->canShow();
}

const bool LEDTable::isOutsideTransformed(const int x, const int y)
{
  return x < 0 || x >= originalWidth() || y < 0 || y >= originalHeight();
}

void LEDTable::updateColor(uint16_t index, Color color)
{
  if (!strip || color == color_transparent) return;
#ifdef USE_SERIAL_CONNECTION
  if (printed_pixels)
  {
    printed_pixels[index] = printed_pixels[index] || strip->getPixelColor(index) != (color & 0xffffff);
  }
#endif
  if (!(color & 0xff000000))
  {
    strip->setPixelColor(index, color);
    return;
  }
  // mixing different transparencies
  uint16_t transparency = ALPHA(color);
  Color color0 = strip->getPixelColor(index);
  uint16_t red = (RED(color) * (256 - transparency) + RED(color0) * transparency) >> 8;
  uint16_t green = (GREEN(color) * (256 - transparency) + GREEN(color0) * transparency) >> 8;
  uint16_t blue = (BLUE(color) * (256 - transparency) + BLUE(color0) * transparency) >> 8;
  strip->setPixelColor(index, red, green, blue);
}

void LEDTable::updateColorTransformed(int x, int y, Color color)
{
  int index = stripeIndexTransformed(x, y);
  updateColor(index, color);
}

void LEDTable::fill(Color color)
{
  for (int i = width() * height() - 1; i >= 0; i--) {
    updateColor(i, color);
  }
}

void LEDTable::fill(int x, int y, Color color)
{
  pixelOrder(&x, &y);
  if (isOutsideTransformed(x, y)) return;
  updateColorTransformed(x, y, color);
}

void LEDTable::fill(int x1, int y1, int x2, int y2, Color color)
{
  int x_min = min(x1, x2);
  int x_max = max(x1, x2);
  int y_min = min(y1, y2);
  int y_max = max(y1, y2);
  for (int x = x_min; x < x_max; x++)
  {
    for (int y = y_min; y < y_max; y++)
    {
      fill(x, y, color);
    }
  }
}

Color LEDTable::at(int x, int y)
{
  if (!strip)
  {
    return color_default;
  }
  pixelOrder(&x, &y);
  if (isOutsideTransformed(x, y)) return color_default;
  return strip->getPixelColor(x + y * originalWidth()) & 0xffffff;
}

void LEDTable::ellipse(int x1, int y1, int x2, int y2, Color color)
{
  // TODO: This can overflow if we have more that 128x128 pixel size.
  //       We could use floats but that could be more overhead.
  int x_min = min(x1, x2) - 1;
  int x_max = max(x1, x2);
  int y_min = min(y1, y2) - 1;
  int y_max = max(y1, y2);
  int width = x_max - x_min;
  int height = y_max - y_min;
  int x0_2 = x_max + x_min;
  int y0_2 = y_max + y_min;
  long radius = height;
  radius *= width;
  radius *= radius; // radius = 4 * width * width * height * height
  for (int x = x_min; x < x_max; x++)
  {
    for (int y = y_min; y < y_max; y++)
    {
      long k1 = abs(x+x - x0_2);
      k1 *= height;
      long k2 = abs(y+y - y0_2);
      k2 *= width;
      if (k1*k1 + k2*k2 < radius)
      {
        fill(x, y, color);
      }
    }
  }
}

void LEDTable::line(int px, int py, int qx, int qy, Color color)
{
#define FILL(x, y) if (x_and_y_are_switched) { fill(y, x, color); } else { fill(x, y, color); };
#define SWITCH(x, y) ;x-= y; y+= x; x = y - x;

  int x_direction = qx > px ? 1 : -1;
  int y_direction = qy > py ? 1 : -1;
  int dx = qx - px;
  int dy = qy - py;
  bool x_and_y_are_switched = abs(dx) < abs(dy);
  if (x_and_y_are_switched)
  {
    SWITCH(x_direction, y_direction);
    SWITCH(dx, dy);
    SWITCH(px, py);
    SWITCH(qx, qy);
  }
  // after this we know that the slope <= 45°
  if (py == qy)
  {
    for (int x = px; x != qx + x_direction; x+= x_direction)
    {
      FILL(x, py);
    }
    return;
  }
  int last_x = px;
  int last_y = py;
  long last_y_dx = long(py) * long(dx);
  while (last_x != qx || last_y != qy)
  {
    FILL(last_x, last_y);
    // compute the new positions
    int new_x = last_x + x_direction;
    int x1 = new_x;
    int y1 = last_y;
    int x2 = new_x;
    int y2 = last_y + y_direction;
    long new_y_dx = long(new_x - px) * long(dy) + long(py) * long(dx);
    int y1_dx = last_y_dx; // = y1 * dx
    int y2_dx = y2 * dx;
    last_x = new_x;
    if (abs(new_y_dx - y1_dx) < abs(new_y_dx - y2_dx))
    {
      last_y = y1;
      last_y_dx = y1_dx;
    } else {
      last_y = y2;
      last_y_dx = y2_dx;
    }
  }
  FILL(qx, qy);

#undef FILL
#undef SWITCH
}

// always use lines with number of points dividable by two to create larger lines
// -> log memory overhead
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, Color color)
{
  line(x1, y1, x2, y2, color);
  line(x3, y3, x2, y2, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Color color)
{
  line(x1, y1, x2, y2, color);
  line(x3, y3, x2, y2, color);
  line(x3, y3, x4, y4, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, color);
  line(x6, y6, x5, y5, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, int x7, int y7, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, x6, y6, x7, y7, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, int x7, int y7, int x8, int y8, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, x6, y6, x7, y7, color);
  line(x7, y7, x8, y8, color);
}

void LEDTable::print(Text* text, int x, int y, Color text_color, Color background_color) {
  text->printOn(this, x, y, text_color, background_color);
}

const int LEDTable::originalHeight()
{
  return _height;
}

const int LEDTable::originalWidth()
{
  return _width;
}

const int LEDTable::height()
{
  if (_widthAndHeightAreSwitched) return _width;
  return _height;
}

const int LEDTable::width()
{
  if (_widthAndHeightAreSwitched) return _height;
  return _width;
}

uint8_t LEDTable::brightness()
{
  if (!strip)
  {
    return 0;
  }
  return strip->getBrightness();
}
void LEDTable::brightness(uint8_t brightness)
{
  if (strip)
  {
    strip->setBrightness(brightness);
  }
}

const int LEDTable::maxX()
{
  return width() - 1;
}

const int LEDTable::maxY()
{
  return height() - 1;
}

const int LEDTable::minX()
{
  return 0;
}

const int LEDTable::minY()
{
  return 0;
}

const int LEDTable::middleX()
{
  return width() / 2;
}

const int LEDTable::middleY()
{
  return height() / 2;
}

bool LEDTable::isInside(int x, int y)
{
  return !isOutside(x, y);
}

bool LEDTable::isOutside(int x, int y)
{
  pixelOrder(&x, &y);
  return isOutsideTransformed(x, y);
}

void LEDTable::pixelOrder(int* x, int*y)
{
  _pixelorder(this, x, y);
}

int LEDTable::stripeIndex(int x, int y)
{
  pixelOrder(&x, &y);
  return stripeIndexTransformed(x, y);
}

int LEDTable::stripeIndexTransformed(int x, int y)
{
  return x + y * originalWidth();
}

uint8_t LEDTable::brightnessAt(int x, int y)
{
  Color color = at(x, y);
  // http://stackoverflow.com/questions/15326911/how-to-access-global-variable-when-there-is-a-local-and-global-conflict
  extern const uint8_t brightness(const Color color);
  return brightness(color);
}

#ifdef USE_SERIAL_CONNECTION
void LEDTable::printToSerial(HardwareSerial* serial)
{
  if (!printed_pixels)
  {
    int number_of_pixels = originalWidth() * originalHeight();
    printed_pixels = (bool*)(malloc(number_of_pixels));
    if (printed_pixels)
    {
      memset(printed_pixels, true, number_of_pixels);
    }
    serial->println();
  }
  serial->print(SERIAL_COMMAND_CHARACTER);
  serial->print("p ");
  serial->println(height());
  for (int y = 0; y < height(); y++)
  {
    int skipped_pixels = 0;
    for (int x = 0; x < width(); x++)
    {
      skipped_pixels++;
      const int printedPixelsIndex = stripeIndex(x, y);
      Color color = at(x, y);
      if ((!printed_pixels) || (printed_pixels[printedPixelsIndex]))
      {
        for (int i = skipped_pixels ; i > 0 ; i--)
        {
          serial->print("#");
        }
        skipped_pixels = 0;
        serial->print(color & 0xffffff, HEX);
        if (printed_pixels)
        {
          printed_pixels[printedPixelsIndex] = false;
        }
      }
    }
    serial->println();
  }
}

void LEDTable::printPixelOrderToSerial(HardwareSerial* serial)
{
  serial->print(SERIAL_COMMAND_CHARACTER);
  serial->print("o ");
  serial->println(this->originalHeight());
  for (int y = 0; y < originalHeight(); y++)
  {
    for (int x = 0; x < originalWidth(); x++)
    {
      int stripeIndex = this->stripeIndex(x, y);
      if (x != 0)
      {
        serial->print(" ");
      }
      serial->print(stripeIndex);
    }
    serial->println();
  }
}

#endif
<commit_msg>fixed bug of prntg pixel order when x and y are flipped<commit_after>#include "ledtable.h"

LEDTable::LEDTable(int pin,
    int width,
    int height,
    PixelOrder pixelorder,
    neoPixelType strip_type) : _width(width), _height(height), _pixelorder(pixelorder), strip_type(strip_type), pin(pin)
{
  /* determine whether the table is rotated by 90° */
  int x = originalWidth() - 1;
  int y = originalHeight() - 1;
  pixelOrder(&x, &y);
  _widthAndHeightAreSwitched = isOutsideTransformed(x, y);
  /* create the strip */
  strip = NULL;
#ifdef USE_SERIAL_CONNECTION
  printed_pixels = NULL;
#endif
}

LEDTable::~LEDTable()
{
  if (strip)
  {
    delete strip;
  }
#ifdef USE_SERIAL_CONNECTION
  free(printed_pixels);
#endif
}

void LEDTable::begin()
{
  if (!strip)
  {
    strip = new Adafruit_NeoPixel(this->originalWidth() * this->originalHeight(), pin, strip_type);
  }
  if (strip)
  {
    strip->begin();
  }
}

void LEDTable::show()
{
  if (strip)
  {
    strip->show();
  }
}

boolean LEDTable::canShow()
{
  return strip && strip->canShow();
}

const bool LEDTable::isOutsideTransformed(const int x, const int y)
{
  return x < 0 || x >= originalWidth() || y < 0 || y >= originalHeight();
}

void LEDTable::updateColor(uint16_t index, Color color)
{
  if (!strip || color == color_transparent) return;
#ifdef USE_SERIAL_CONNECTION
  if (printed_pixels)
  {
    printed_pixels[index] = printed_pixels[index] || strip->getPixelColor(index) != (color & 0xffffff);
  }
#endif
  if (!(color & 0xff000000))
  {
    strip->setPixelColor(index, color);
    return;
  }
  // mixing different transparencies
  uint16_t transparency = ALPHA(color);
  Color color0 = strip->getPixelColor(index);
  uint16_t red = (RED(color) * (256 - transparency) + RED(color0) * transparency) >> 8;
  uint16_t green = (GREEN(color) * (256 - transparency) + GREEN(color0) * transparency) >> 8;
  uint16_t blue = (BLUE(color) * (256 - transparency) + BLUE(color0) * transparency) >> 8;
  strip->setPixelColor(index, red, green, blue);
}

void LEDTable::updateColorTransformed(int x, int y, Color color)
{
  int index = stripeIndexTransformed(x, y);
  updateColor(index, color);
}

void LEDTable::fill(Color color)
{
  for (int i = width() * height() - 1; i >= 0; i--) {
    updateColor(i, color);
  }
}

void LEDTable::fill(int x, int y, Color color)
{
  pixelOrder(&x, &y);
  if (isOutsideTransformed(x, y)) return;
  updateColorTransformed(x, y, color);
}

void LEDTable::fill(int x1, int y1, int x2, int y2, Color color)
{
  int x_min = min(x1, x2);
  int x_max = max(x1, x2);
  int y_min = min(y1, y2);
  int y_max = max(y1, y2);
  for (int x = x_min; x < x_max; x++)
  {
    for (int y = y_min; y < y_max; y++)
    {
      fill(x, y, color);
    }
  }
}

Color LEDTable::at(int x, int y)
{
  if (!strip)
  {
    return color_default;
  }
  pixelOrder(&x, &y);
  if (isOutsideTransformed(x, y)) return color_default;
  return strip->getPixelColor(x + y * originalWidth()) & 0xffffff;
}

void LEDTable::ellipse(int x1, int y1, int x2, int y2, Color color)
{
  // TODO: This can overflow if we have more that 128x128 pixel size.
  //       We could use floats but that could be more overhead.
  int x_min = min(x1, x2) - 1;
  int x_max = max(x1, x2);
  int y_min = min(y1, y2) - 1;
  int y_max = max(y1, y2);
  int width = x_max - x_min;
  int height = y_max - y_min;
  int x0_2 = x_max + x_min;
  int y0_2 = y_max + y_min;
  long radius = height;
  radius *= width;
  radius *= radius; // radius = 4 * width * width * height * height
  for (int x = x_min; x < x_max; x++)
  {
    for (int y = y_min; y < y_max; y++)
    {
      long k1 = abs(x+x - x0_2);
      k1 *= height;
      long k2 = abs(y+y - y0_2);
      k2 *= width;
      if (k1*k1 + k2*k2 < radius)
      {
        fill(x, y, color);
      }
    }
  }
}

void LEDTable::line(int px, int py, int qx, int qy, Color color)
{
#define FILL(x, y) if (x_and_y_are_switched) { fill(y, x, color); } else { fill(x, y, color); };
#define SWITCH(x, y) ;x-= y; y+= x; x = y - x;

  int x_direction = qx > px ? 1 : -1;
  int y_direction = qy > py ? 1 : -1;
  int dx = qx - px;
  int dy = qy - py;
  bool x_and_y_are_switched = abs(dx) < abs(dy);
  if (x_and_y_are_switched)
  {
    SWITCH(x_direction, y_direction);
    SWITCH(dx, dy);
    SWITCH(px, py);
    SWITCH(qx, qy);
  }
  // after this we know that the slope <= 45°
  if (py == qy)
  {
    for (int x = px; x != qx + x_direction; x+= x_direction)
    {
      FILL(x, py);
    }
    return;
  }
  int last_x = px;
  int last_y = py;
  long last_y_dx = long(py) * long(dx);
  while (last_x != qx || last_y != qy)
  {
    FILL(last_x, last_y);
    // compute the new positions
    int new_x = last_x + x_direction;
    int x1 = new_x;
    int y1 = last_y;
    int x2 = new_x;
    int y2 = last_y + y_direction;
    long new_y_dx = long(new_x - px) * long(dy) + long(py) * long(dx);
    int y1_dx = last_y_dx; // = y1 * dx
    int y2_dx = y2 * dx;
    last_x = new_x;
    if (abs(new_y_dx - y1_dx) < abs(new_y_dx - y2_dx))
    {
      last_y = y1;
      last_y_dx = y1_dx;
    } else {
      last_y = y2;
      last_y_dx = y2_dx;
    }
  }
  FILL(qx, qy);

#undef FILL
#undef SWITCH
}

// always use lines with number of points dividable by two to create larger lines
// -> log memory overhead
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, Color color)
{
  line(x1, y1, x2, y2, color);
  line(x3, y3, x2, y2, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, Color color)
{
  line(x1, y1, x2, y2, color);
  line(x3, y3, x2, y2, color);
  line(x3, y3, x4, y4, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, color);
  line(x6, y6, x5, y5, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, int x7, int y7, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, x6, y6, x7, y7, color);
}
void LEDTable::line(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int x5, int y5, int x6, int y6, int x7, int y7, int x8, int y8, Color color)
{
  line(x1, y1, x2, y2, x3, y3, x4, y4, color);
  line(x4, y4, x5, y5, x6, y6, x7, y7, color);
  line(x7, y7, x8, y8, color);
}

void LEDTable::print(Text* text, int x, int y, Color text_color, Color background_color) {
  text->printOn(this, x, y, text_color, background_color);
}

const int LEDTable::originalHeight()
{
  return _height;
}

const int LEDTable::originalWidth()
{
  return _width;
}

const int LEDTable::height()
{
  if (_widthAndHeightAreSwitched) return _width;
  return _height;
}

const int LEDTable::width()
{
  if (_widthAndHeightAreSwitched) return _height;
  return _width;
}

uint8_t LEDTable::brightness()
{
  if (!strip)
  {
    return 0;
  }
  return strip->getBrightness();
}
void LEDTable::brightness(uint8_t brightness)
{
  if (strip)
  {
    strip->setBrightness(brightness);
  }
}

const int LEDTable::maxX()
{
  return width() - 1;
}

const int LEDTable::maxY()
{
  return height() - 1;
}

const int LEDTable::minX()
{
  return 0;
}

const int LEDTable::minY()
{
  return 0;
}

const int LEDTable::middleX()
{
  return width() / 2;
}

const int LEDTable::middleY()
{
  return height() / 2;
}

bool LEDTable::isInside(int x, int y)
{
  return !isOutside(x, y);
}

bool LEDTable::isOutside(int x, int y)
{
  pixelOrder(&x, &y);
  return isOutsideTransformed(x, y);
}

void LEDTable::pixelOrder(int* x, int*y)
{
  _pixelorder(this, x, y);
}

int LEDTable::stripeIndex(int x, int y)
{
  pixelOrder(&x, &y);
  return stripeIndexTransformed(x, y);
}

int LEDTable::stripeIndexTransformed(int x, int y)
{
  return x + y * originalWidth();
}

uint8_t LEDTable::brightnessAt(int x, int y)
{
  Color color = at(x, y);
  // http://stackoverflow.com/questions/15326911/how-to-access-global-variable-when-there-is-a-local-and-global-conflict
  extern const uint8_t brightness(const Color color);
  return brightness(color);
}

#ifdef USE_SERIAL_CONNECTION
void LEDTable::printToSerial(HardwareSerial* serial)
{
  if (!printed_pixels)
  {
    int number_of_pixels = originalWidth() * originalHeight();
    printed_pixels = (bool*)(malloc(number_of_pixels));
    if (printed_pixels)
    {
      memset(printed_pixels, true, number_of_pixels);
    }
    serial->println();
  }
  serial->print(SERIAL_COMMAND_CHARACTER);
  serial->print("p ");
  serial->println(height());
  for (int y = 0; y < height(); y++)
  {
    int skipped_pixels = 0;
    for (int x = 0; x < width(); x++)
    {
      skipped_pixels++;
      const int printedPixelsIndex = stripeIndex(x, y);
      Color color = at(x, y);
      if ((!printed_pixels) || (printed_pixels[printedPixelsIndex]))
      {
        for (int i = skipped_pixels ; i > 0 ; i--)
        {
          serial->print("#");
        }
        skipped_pixels = 0;
        serial->print(color & 0xffffff, HEX);
        if (printed_pixels)
        {
          printed_pixels[printedPixelsIndex] = false;
        }
      }
    }
    serial->println();
  }
}

void LEDTable::printPixelOrderToSerial(HardwareSerial* serial)
{
  serial->print(SERIAL_COMMAND_CHARACTER);
  serial->print("o ");
  serial->println(this->height());
  for (int y = 0; y < height(); y++)
  {
    for (int x = 0; x < width(); x++)
    {
      int stripeIndex = this->stripeIndex(x, y);
      if (x != 0)
      {
        serial->print(" ");
      }
      serial->print(stripeIndex);
    }
    serial->println();
  }
}

#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "excelfilter.hxx"

#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include "oox/helper/binaryinputstream.hxx"
#include "biffinputstream.hxx"
#include "excelchartconverter.hxx"
#include "excelvbaproject.hxx"
#include "stylesbuffer.hxx"
#include "themebuffer.hxx"
#include "workbookfragment.hxx"

namespace oox {
namespace xls {

// ============================================================================

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::oox::core;

using ::rtl::OUString;
using ::oox::drawingml::table::TableStyleListPtr;

// ============================================================================

ExcelFilterBase::ExcelFilterBase() :
    mpBookGlob( 0 )
{
}

ExcelFilterBase::~ExcelFilterBase()
{
    OSL_ENSURE( !mpBookGlob, "ExcelFilterBase::~ExcelFilterBase - workbook data not cleared" );
}

void ExcelFilterBase::registerWorkbookGlobals( WorkbookGlobals& rBookGlob )
{
    mpBookGlob = &rBookGlob;
}

WorkbookGlobals& ExcelFilterBase::getWorkbookGlobals() const
{
    OSL_ENSURE( mpBookGlob, "ExcelFilterBase::getWorkbookGlobals - missing workbook data" );
    return *mpBookGlob;
}

void ExcelFilterBase::unregisterWorkbookGlobals()
{
    mpBookGlob = 0;
}

// ============================================================================

OUString SAL_CALL ExcelFilter_getImplementationName() throw()
{
    return OUString( "com.sun.star.comp.oox.xls.ExcelFilter" );
}

Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw()
{
    Sequence< OUString > aSeq( 2 );
    aSeq[ 0 ] = "com.sun.star.document.ImportFilter";
    aSeq[ 1 ] = "com.sun.star.document.ExportFilter";
    return aSeq;
}

Reference< XInterface > SAL_CALL ExcelFilter_createInstance(
        const Reference< XComponentContext >& rxContext ) throw( Exception )
{
    return static_cast< ::cppu::OWeakObject* >( new ExcelFilter( rxContext ) );
}

// ----------------------------------------------------------------------------

ExcelFilter::ExcelFilter( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
    XmlFilterBase( rxContext )
{
}

ExcelFilter::~ExcelFilter()
{
}

bool ExcelFilter::importDocument() throw()
{
    /*  To activate the XLSX/XLSB dumper, insert the full path to the file
        file:///<path-to-oox-module>/source/dump/xlsbdumper.ini
        into the environment variable OOO_XLSBDUMPER and start the office with
        this variable (nonpro only). */
    //OOX_DUMP_FILE( ::oox::dump::xlsb::Dumper );

    OUString aWorkbookPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "officeDocument" ) );
    if( aWorkbookPath.isEmpty() )
        return false;

    /*  Construct the WorkbookGlobals object referred to by every instance of
        the class WorkbookHelper, and execute the import filter by constructing
        an instance of WorkbookFragment and loading the file. */
    WorkbookGlobalsRef xBookGlob = WorkbookHelper::constructGlobals( *this );
    if ( xBookGlob.get() && importFragment( new WorkbookFragment( *xBookGlob, aWorkbookPath ) ) )
    {
        importDocumentProperties();
        return true;
    }
    return false;
}

bool ExcelFilter::exportDocument() throw()
{
    return false;
}

const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const
{
    return &WorkbookHelper( getWorkbookGlobals() ).getTheme();
}

::oox::vml::Drawing* ExcelFilter::getVmlDrawing()
{
    return 0;
}

const TableStyleListPtr ExcelFilter::getTableStyles()
{
    return TableStyleListPtr();
}

::oox::drawingml::chart::ChartConverter* ExcelFilter::getChartConverter()
{
    return WorkbookHelper( getWorkbookGlobals() ).getChartConverter();
}

GraphicHelper* ExcelFilter::implCreateGraphicHelper() const
{
    return new ExcelGraphicHelper( getWorkbookGlobals() );
}

::oox::ole::VbaProject* ExcelFilter::implCreateVbaProject() const
{
    return new ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
}

sal_Bool SAL_CALL ExcelFilter::filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rDescriptor ) throw( ::com::sun::star::uno::RuntimeException )
{
    if ( XmlFilterBase::filter( rDescriptor ) )
        return true;

    if ( isExportFilter() )
    {
        Reference< XExporter > xExporter( getServiceFactory()->createInstance( "com.sun.star.comp.oox.ExcelFilterExport" ), UNO_QUERY );

        if ( xExporter.is() )
        {
            Reference< XComponent > xDocument( getModel(), UNO_QUERY );
            Reference< XFilter > xFilter( xExporter, UNO_QUERY );

            if ( xFilter.is() )
            {
                xExporter->setSourceDocument( xDocument );
                if ( xFilter->filter( rDescriptor ) )
                    return true;
            }
        }
    }

    return false;
}

OUString ExcelFilter::implGetImplementationName() const
{
    return ExcelFilter_getImplementationName();
}

} // namespace xls
} // namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>we need to catch the exception here, fdo#57451<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "excelfilter.hxx"

#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include "oox/helper/binaryinputstream.hxx"
#include "biffinputstream.hxx"
#include "excelchartconverter.hxx"
#include "excelvbaproject.hxx"
#include "stylesbuffer.hxx"
#include "themebuffer.hxx"
#include "workbookfragment.hxx"

namespace oox {
namespace xls {

// ============================================================================

using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::sheet;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::oox::core;

using ::rtl::OUString;
using ::oox::drawingml::table::TableStyleListPtr;

// ============================================================================

ExcelFilterBase::ExcelFilterBase() :
    mpBookGlob( 0 )
{
}

ExcelFilterBase::~ExcelFilterBase()
{
    OSL_ENSURE( !mpBookGlob, "ExcelFilterBase::~ExcelFilterBase - workbook data not cleared" );
}

void ExcelFilterBase::registerWorkbookGlobals( WorkbookGlobals& rBookGlob )
{
    mpBookGlob = &rBookGlob;
}

WorkbookGlobals& ExcelFilterBase::getWorkbookGlobals() const
{
    OSL_ENSURE( mpBookGlob, "ExcelFilterBase::getWorkbookGlobals - missing workbook data" );
    return *mpBookGlob;
}

void ExcelFilterBase::unregisterWorkbookGlobals()
{
    mpBookGlob = 0;
}

// ============================================================================

OUString SAL_CALL ExcelFilter_getImplementationName() throw()
{
    return OUString( "com.sun.star.comp.oox.xls.ExcelFilter" );
}

Sequence< OUString > SAL_CALL ExcelFilter_getSupportedServiceNames() throw()
{
    Sequence< OUString > aSeq( 2 );
    aSeq[ 0 ] = "com.sun.star.document.ImportFilter";
    aSeq[ 1 ] = "com.sun.star.document.ExportFilter";
    return aSeq;
}

Reference< XInterface > SAL_CALL ExcelFilter_createInstance(
        const Reference< XComponentContext >& rxContext ) throw( Exception )
{
    return static_cast< ::cppu::OWeakObject* >( new ExcelFilter( rxContext ) );
}

// ----------------------------------------------------------------------------

ExcelFilter::ExcelFilter( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
    XmlFilterBase( rxContext )
{
}

ExcelFilter::~ExcelFilter()
{
}

bool ExcelFilter::importDocument() throw()
{
    /*  To activate the XLSX/XLSB dumper, insert the full path to the file
        file:///<path-to-oox-module>/source/dump/xlsbdumper.ini
        into the environment variable OOO_XLSBDUMPER and start the office with
        this variable (nonpro only). */
    //OOX_DUMP_FILE( ::oox::dump::xlsb::Dumper );

    OUString aWorkbookPath = getFragmentPathFromFirstType( CREATE_OFFICEDOC_RELATION_TYPE( "officeDocument" ) );
    if( aWorkbookPath.isEmpty() )
        return false;

    /*  Construct the WorkbookGlobals object referred to by every instance of
        the class WorkbookHelper, and execute the import filter by constructing
        an instance of WorkbookFragment and loading the file. */
    WorkbookGlobalsRef xBookGlob = WorkbookHelper::constructGlobals( *this );
    if ( xBookGlob.get() && importFragment( new WorkbookFragment( *xBookGlob, aWorkbookPath ) ) )
    {
        try
        {
            importDocumentProperties();
        }
        catch( const Exception& e )
        {
            SAL_WARN("sc", "exception when importing document properties " << e.Message);
        }
        return true;
    }
    return false;
}

bool ExcelFilter::exportDocument() throw()
{
    return false;
}

const ::oox::drawingml::Theme* ExcelFilter::getCurrentTheme() const
{
    return &WorkbookHelper( getWorkbookGlobals() ).getTheme();
}

::oox::vml::Drawing* ExcelFilter::getVmlDrawing()
{
    return 0;
}

const TableStyleListPtr ExcelFilter::getTableStyles()
{
    return TableStyleListPtr();
}

::oox::drawingml::chart::ChartConverter* ExcelFilter::getChartConverter()
{
    return WorkbookHelper( getWorkbookGlobals() ).getChartConverter();
}

GraphicHelper* ExcelFilter::implCreateGraphicHelper() const
{
    return new ExcelGraphicHelper( getWorkbookGlobals() );
}

::oox::ole::VbaProject* ExcelFilter::implCreateVbaProject() const
{
    return new ExcelVbaProject( getComponentContext(), Reference< XSpreadsheetDocument >( getModel(), UNO_QUERY ) );
}

sal_Bool SAL_CALL ExcelFilter::filter( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rDescriptor ) throw( ::com::sun::star::uno::RuntimeException )
{
    if ( XmlFilterBase::filter( rDescriptor ) )
        return true;

    if ( isExportFilter() )
    {
        Reference< XExporter > xExporter( getServiceFactory()->createInstance( "com.sun.star.comp.oox.ExcelFilterExport" ), UNO_QUERY );

        if ( xExporter.is() )
        {
            Reference< XComponent > xDocument( getModel(), UNO_QUERY );
            Reference< XFilter > xFilter( xExporter, UNO_QUERY );

            if ( xFilter.is() )
            {
                xExporter->setSourceDocument( xDocument );
                if ( xFilter->filter( rDescriptor ) )
                    return true;
            }
        }
    }

    return false;
}

OUString ExcelFilter::implGetImplementationName() const
{
    return ExcelFilter_getImplementationName();
}

} // namespace xls
} // namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <cstring>

#include "OpenCLHelper.h"
#include "stringhelper.h"
#include "Timer.h"
#include "test/TestArgsParser.h"
#include "test/SpeedTemplates.h"

using namespace std;

// for use in conjunction with http://www.cs.berkeley.edu/~volkov/volkov10-GTC.pdf
int main( int argc, char *argv[] ) {
    OpenCLHelper *cl = OpenCLHelper::createForFirstGpuOtherwiseCpu();

//    int its = 10000000;
    int numFloats = 50000000;
    int workgroupSize = 512;
    bool optimizerOn = true;
    int count = 1;
//    bool enableMad = true;
    int kernelVersion = 1;

    TestArgsParser args( argc, argv );
//    args._arg( "its", &its );
    args._arg( "n", &numFloats );
    args._arg( "workgroupsize", &workgroupSize );
    args._arg( "opt", &optimizerOn );
    args._arg( "count", &count );
    args._arg( "kernel", &kernelVersion );
//    args._arg( "mad", &enableMad );
    args._go();
    cout << "values:" << endl;
    args._printValues();

    count = OpenCLHelper::getNextPower2( count );
    int thiscount = count;
    int shift = 0;
    while( thiscount > 1 ) {
        thiscount >>= 1;
        shift++;
    }
    cout << "count: " << count << " shift: " << shift << endl;

//    cout << "its: " << its << " workgroupsize: " << workgroupSize << " optimizer: " << optimizerOn << endl;

    string kernelSource1 = R"DELIM(
        kernel void memcpy( global float const*src, global float *dest) {
            if( get_global_id(0) < N ) {
                float a = src[get_global_id(0)];
                dest[get_global_id(0)] = a;
            }
        }
    )DELIM";

    string kernelSource2 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            if( get_global_id(0) < N ) {
                dest[get_global_id(0)] = src[get_global_id(0)];
            }
        }
    )DELIM";

    string kernelSource3 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            dest[get_global_id(0)] = src[get_global_id(0)];
        }
    )DELIM";

    string kernelSource4 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            float a[COUNT];
            int offset = get_global_id(0) << SHIFT;
//            if( offset < N ) {
            if( get_global_id(0) < ( N >> SHIFT ) ) {
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    a[i] = src[ offset + i ];
                }
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    dest[ offset + i ] = a[i];
                }
            }
        }
    )DELIM";

    string kernelSource5 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            float a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( offset < N ) {
            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = src[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    dest[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string kernelSource6 = R"DELIM(
        #define f4(var) ( (global float4*)(var) )

        kernel void memcpy(global float const*src, global float *dest) {
            float4 a[COUNT];
            int offset = get_global_id(0) << SHIFT;
            if( get_global_id(0) < ( N >> SHIFT ) ) {
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    a[i] = f4(src)[ offset + i ];
                }
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    f4(dest)[ offset + i ] = a[i];
                }
            }
        }
    )DELIM";

    string kernelSource7 = R"DELIM(
        #define f4(var) ( (global float4*)(var) )

        kernel void memcpy(global float const*src, global float *dest) {
            float4 a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
            if( ( ( offset + {{COUNT}} - 1) << 2 ) < {{N}} ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = f4(src)[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    f4(dest)[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string kernelSource8 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            local float a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
            if( ( ( offset + {{COUNT}} - 1) << 2 ) < {{N}} ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = f4(src)[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    f4(dest)[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string options = "";
    if( !optimizerOn ) {
        options += " -cl-opt-disable";
    }
//    if( enableMad ) {
        options += " -cl-mad-enable";
//    }
    options += " -D COUNT=" + toString( count );
    options += " -D SHIFT=" + toString( shift );
//    if( kernelVersion == 1 && count == 4 ) {
//        options += " -D dOn";
//    }
    options += " -cl-single-precision-constant";
//    options += " -D N_ITERATIONS=" + toString( its );
    options += " -D N=" + toString( numFloats );
//    options += " -D UNROLL=" + toString( unroll );

    string kernelSource = "";
    if( kernelVersion == 1 ) {
        kernelSource = kernelSource1;
    } else if( kernelVersion == 2 ) {
        kernelSource = kernelSource2;
    } else if( kernelVersion == 3 ) {
        kernelSource = kernelSource3;
    } else if( kernelVersion == 4 ) {
        kernelSource = kernelSource4;
    } else if( kernelVersion == 5 ) {
        SpeedTemplates::Template mytemplate( kernelSource5 );
        mytemplate.setValue( "COUNT", count );
        mytemplate.setValue( "N", numFloats );
        mytemplate.setValue( "SHIFT", shift );
//        mytemplate.setValue( "unroll", unroll );
        string renderedSource = mytemplate.render();
        cout << "rendered source: [" << renderedSource << "]" << endl;
        kernelSource = renderedSource;
    } else if( kernelVersion == 6 ) {
        kernelSource = kernelSource6;
    } else if( kernelVersion == 7 ) {
        SpeedTemplates::Template mytemplate( kernelSource7 );
        mytemplate.setValue( "N", numFloats );
        mytemplate.setValue( "COUNT", count );
        mytemplate.setValue( "SHIFT", shift );
//        mytemplate.setValue( "unroll", unroll );
        string renderedSource = mytemplate.render();
        cout << "rendered source: [" << renderedSource << "]" << endl;
        kernelSource = renderedSource;
    } else {
        throw runtime_error("kernel version " + toString( kernelVersion ) + " not implemented");
    }

    CLKernel *kernel = cl->buildKernelFromString( kernelSource, "memcpy", options );

    float *src = new float[numFloats];
    for( int i = 0; i < numFloats; i++ ) {
        src[i] = 2.0f;
    }
    float *dest = new float[numFloats + count];
    memset( dest, 0, ( numFloats + count ) * sizeof(float) );

    CLWrapper *destWrapper = cl->wrap( numFloats + count, dest );
    CLWrapper *srcWrapper = cl->wrap( numFloats + count, src );
    destWrapper->createOnDevice();
    srcWrapper->copyToDevice();
    kernel->in( srcWrapper );
    kernel->out( destWrapper );
    int numWorkgroups = ( numFloats / count + workgroupSize - 1 ) / workgroupSize;
    if( kernelVersion >= 6 ) {
        numWorkgroups = ( numFloats / count / 4 + workgroupSize - 1 ) / workgroupSize;
    }
    cl->finish(); // just in case...
    Timer timer;
    kernel->run_1d( numWorkgroups * workgroupSize, workgroupSize );
    cl->finish();
    float kernelTime = timer.lap();
    cout << "time: " << kernelTime << "ms" << endl;
//    cout << stuff[0] << " " << stuff[1] << endl;

    float kernelTimeSeconds = kernelTime / 1000.0f;

    float throughputGbytes = numFloats * 4.0f  / 1024 / 1024 / 1024;
//    if( kernelVersion >= 4 ) {
//        throughputGbytes *= count;
//    }
    float throughputGbytespersec = throughputGbytes / kernelTimeSeconds;
//    float throughputGflops = (float)its * workgroupSize / kernelTimeSeconds / 1024 / 1024 / 1024;

    cout << "throughput: " << throughputGbytespersec << "GB/s" << endl;

    // check the memory copied...
    destWrapper->copyToHost();
    int errCount = 0;
    for( int i = 0; i < numFloats; i++ ) {
        if( dest[i] != 2.0f ) {
            if( errCount > 5 ) {
                cout << "..." << endl;
                break;
            }
            cout << "DIFF: dest[" << i << "]=" << dest[i] << endl;
            errCount++;
        }
    }
    for( int i = 0; i < count; i++ ) {
        if( dest[i + numFloats] != 0.0f ) {
            if( errCount > 5 ) {
                cout << "..." << endl;
                break;
            }
            cout << "DIFF: dest[" << ( i + numFloats ) << "]=" << dest[i + numFloats] << endl;
            errCount++;
        }
    }

    delete destWrapper;
    delete srcWrapper;
    delete[] src;
    delete[] dest;
    delete kernel;
    delete cl;

    return 0;
}

<commit_msg>more bugs in testmemperf...<commit_after>#include <iostream>
#include <string>
#include <cstring>

#include "OpenCLHelper.h"
#include "stringhelper.h"
#include "Timer.h"
#include "test/TestArgsParser.h"
#include "test/SpeedTemplates.h"

using namespace std;

// for use in conjunction with http://www.cs.berkeley.edu/~volkov/volkov10-GTC.pdf
int main( int argc, char *argv[] ) {
    OpenCLHelper *cl = OpenCLHelper::createForFirstGpuOtherwiseCpu();

//    int its = 10000000;
    int numFloats = 50000000;
    int workgroupSize = 512;
    bool optimizerOn = true;
    int count = 1;
//    bool enableMad = true;
    int kernelVersion = 1;

    TestArgsParser args( argc, argv );
//    args._arg( "its", &its );
    args._arg( "n", &numFloats );
    args._arg( "workgroupsize", &workgroupSize );
    args._arg( "opt", &optimizerOn );
    args._arg( "count", &count );
    args._arg( "kernel", &kernelVersion );
//    args._arg( "mad", &enableMad );
    args._go();
    cout << "values:" << endl;
    args._printValues();

    count = OpenCLHelper::getNextPower2( count );
    int thiscount = count;
    int shift = 0;
    while( thiscount > 1 ) {
        thiscount >>= 1;
        shift++;
    }
    cout << "count: " << count << " shift: " << shift << endl;

//    cout << "its: " << its << " workgroupsize: " << workgroupSize << " optimizer: " << optimizerOn << endl;

    string kernelSource1 = R"DELIM(
        kernel void memcpy( global float const*src, global float *dest) {
            if( get_global_id(0) < N ) {
                float a = src[get_global_id(0)];
                dest[get_global_id(0)] = a;
            }
        }
    )DELIM";

    string kernelSource2 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            if( get_global_id(0) < N ) {
                dest[get_global_id(0)] = src[get_global_id(0)];
            }
        }
    )DELIM";

    string kernelSource3 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            dest[get_global_id(0)] = src[get_global_id(0)];
        }
    )DELIM";

    string kernelSource4 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            float a[COUNT];
            int offset = get_global_id(0) << SHIFT;
//            if( offset < N ) {
            if( offset + COUNT - 1 < N ) {
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    a[i] = src[ offset + i ];
                }
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    dest[ offset + i ] = a[i];
                }
            }
        }
    )DELIM";

    string kernelSource5 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            float a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( offset < N ) {
//            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
            if( offset + {{COUNT}} < {{N}} ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = src[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    dest[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string kernelSource6 = R"DELIM(
        #define f4(var) ( (global float4*)(var) )

        kernel void memcpy(global float const*src, global float *dest) {
            float4 a[COUNT];
            int offset = get_global_id(0) << SHIFT;
            if( get_global_id(0) < ( N >> SHIFT ) ) {
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    a[i] = f4(src)[ offset + i ];
                }
                #pragma unroll COUNT
                for( int i = 0; i < COUNT; i++ ) {
                    f4(dest)[ offset + i ] = a[i];
                }
            }
        }
    )DELIM";

    string kernelSource7 = R"DELIM(
        #define f4(var) ( (global float4*)(var) )

        kernel void memcpy(global float const*src, global float *dest) {
            float4 a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
            if( ( ( offset + {{COUNT}} - 1) << 2 ) < {{N}} ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = f4(src)[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    f4(dest)[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string kernelSource8 = R"DELIM(
        kernel void memcpy(global float const*src, global float *dest) {
            local float a[{{COUNT}}];
            int offset = get_global_id(0) << {{SHIFT}};
//            if( get_global_id(0) < ( {{N}} >> {{SHIFT}} ) ) {
            if( ( ( offset + {{COUNT}} - 1) << 2 ) < {{N}} ) {
                {% for i in range( COUNT ) %}
                    a[{{i}}] = f4(src)[ offset + {{i}} ];
                {% endfor %}
                {% for i in range( COUNT ) %}
                    f4(dest)[ offset + {{i}} ] = a[{{i}}];
                {% endfor %}
            }
        }
    )DELIM";

    string options = "";
    if( !optimizerOn ) {
        options += " -cl-opt-disable";
    }
//    if( enableMad ) {
        options += " -cl-mad-enable";
//    }
    options += " -D COUNT=" + toString( count );
    options += " -D SHIFT=" + toString( shift );
//    if( kernelVersion == 1 && count == 4 ) {
//        options += " -D dOn";
//    }
    options += " -cl-single-precision-constant";
//    options += " -D N_ITERATIONS=" + toString( its );
    options += " -D N=" + toString( numFloats );
//    options += " -D UNROLL=" + toString( unroll );

    string kernelSource = "";
    if( kernelVersion == 1 ) {
        kernelSource = kernelSource1;
    } else if( kernelVersion == 2 ) {
        kernelSource = kernelSource2;
    } else if( kernelVersion == 3 ) {
        kernelSource = kernelSource3;
    } else if( kernelVersion == 4 ) {
        kernelSource = kernelSource4;
    } else if( kernelVersion == 5 ) {
        SpeedTemplates::Template mytemplate( kernelSource5 );
        mytemplate.setValue( "COUNT", count );
        mytemplate.setValue( "N", numFloats );
        mytemplate.setValue( "SHIFT", shift );
//        mytemplate.setValue( "unroll", unroll );
        string renderedSource = mytemplate.render();
        cout << "rendered source: [" << renderedSource << "]" << endl;
        kernelSource = renderedSource;
    } else if( kernelVersion == 6 ) {
        kernelSource = kernelSource6;
    } else if( kernelVersion == 7 ) {
        SpeedTemplates::Template mytemplate( kernelSource7 );
        mytemplate.setValue( "N", numFloats );
        mytemplate.setValue( "COUNT", count );
        mytemplate.setValue( "SHIFT", shift );
//        mytemplate.setValue( "unroll", unroll );
        string renderedSource = mytemplate.render();
        cout << "rendered source: [" << renderedSource << "]" << endl;
        kernelSource = renderedSource;
    } else {
        throw runtime_error("kernel version " + toString( kernelVersion ) + " not implemented");
    }

    CLKernel *kernel = cl->buildKernelFromString( kernelSource, "memcpy", options );

    float *src = new float[numFloats];
    for( int i = 0; i < numFloats; i++ ) {
        src[i] = 2.0f;
    }
    float *dest = new float[numFloats + count];
    memset( dest, 0, ( numFloats + count ) * sizeof(float) );

    CLWrapper *destWrapper = cl->wrap( numFloats + count, dest );
    CLWrapper *srcWrapper = cl->wrap( numFloats + count, src );
    destWrapper->createOnDevice();
    srcWrapper->copyToDevice();
    kernel->in( srcWrapper );
    kernel->out( destWrapper );
    int numWorkgroups = ( numFloats / count + workgroupSize - 1 ) / workgroupSize;
    if( kernelVersion >= 6 ) {
        numWorkgroups = ( numFloats / count / 4 + workgroupSize - 1 ) / workgroupSize;
    }
    cl->finish(); // just in case...
    Timer timer;
    kernel->run_1d( numWorkgroups * workgroupSize, workgroupSize );
    cl->finish();
    float kernelTime = timer.lap();
    cout << "time: " << kernelTime << "ms" << endl;
//    cout << stuff[0] << " " << stuff[1] << endl;

    float kernelTimeSeconds = kernelTime / 1000.0f;

    float throughputGbytes = numFloats * 4.0f  / 1024 / 1024 / 1024;
//    if( kernelVersion >= 4 ) {
//        throughputGbytes *= count;
//    }
    float throughputGbytespersec = throughputGbytes / kernelTimeSeconds;
//    float throughputGflops = (float)its * workgroupSize / kernelTimeSeconds / 1024 / 1024 / 1024;

    cout << "throughput: " << throughputGbytespersec << "GB/s" << endl;

    // check the memory copied...
    destWrapper->copyToHost();
    int errCount = 0;
    for( int i = 0; i < numFloats; i++ ) {
        if( dest[i] != 2.0f ) {
            if( errCount > 5 ) {
                cout << "..." << endl;
                break;
            }
            cout << "DIFF: dest[" << i << "]=" << dest[i] << endl;
            errCount++;
        }
    }
    for( int i = 0; i < count; i++ ) {
        if( dest[i + numFloats] != 0.0f ) {
            if( errCount > 5 ) {
                cout << "..." << endl;
                break;
            }
            cout << "DIFF: dest[" << ( i + numFloats ) << "]=" << dest[i + numFloats] << endl;
            errCount++;
        }
    }

    delete destWrapper;
    delete srcWrapper;
    delete[] src;
    delete[] dest;
    delete kernel;
    delete cl;

    return 0;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/sign.h>
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
#include <util/strencodings.h>
#include <version.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>

#include <algorithm>

CScript ParseScript(const std::string& s)
{
    CScript result;

    static std::map<std::string, opcodetype> mapOpNames;

    if (mapOpNames.empty())
    {
        for (unsigned int op = 0; op <= MAX_OPCODE; op++)
        {
            // Allow OP_RESERVED to get into mapOpNames
            if (op < OP_NOP && op != OP_RESERVED)
                continue;

            const char* name = GetOpName(static_cast<opcodetype>(op));
            if (strcmp(name, "OP_UNKNOWN") == 0)
                continue;
            std::string strName(name);
            mapOpNames[strName] = static_cast<opcodetype>(op);
            // Convenience: OP_ADD and just ADD are both recognized:
            boost::algorithm::replace_first(strName, "OP_", "");
            mapOpNames[strName] = static_cast<opcodetype>(op);
        }
    }

    std::vector<std::string> words;
    boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);

    for (std::vector<std::string>::const_iterator w = words.begin(); w != words.end(); ++w)
    {
        if (w->empty())
        {
            // Empty string, ignore. (boost::split given '' will return one word)
        }
        else if (std::all_of(w->begin(), w->end(), ::IsDigit) ||
            (w->front() == '-' && w->size() > 1 && std::all_of(w->begin()+1, w->end(), ::IsDigit)))
        {
            // Number
            int64_t n = atoi64(*w);
            result << n;
        }
        else if (w->substr(0,2) == "0x" && w->size() > 2 && IsHex(std::string(w->begin()+2, w->end())))
        {
            // Raw hex data, inserted NOT pushed onto stack:
            std::vector<unsigned char> raw = ParseHex(std::string(w->begin()+2, w->end()));
            result.insert(result.end(), raw.begin(), raw.end());
        }
        else if (w->size() >= 2 && w->front() == '\'' && w->back() == '\'')
        {
            // Single-quoted string, pushed as data. NOTE: this is poor-man's
            // parsing, spaces/tabs/newlines in single-quoted strings won't work.
            std::vector<unsigned char> value(w->begin()+1, w->end()-1);
            result << value;
        }
        else if (mapOpNames.count(*w))
        {
            // opcode, e.g. OP_ADD or ADD:
            result << mapOpNames[*w];
        }
        else
        {
            throw std::runtime_error("script parse error");
        }
    }

    return result;
}

// Check that all of the input and output scripts of a transaction contains valid opcodes
static bool CheckTxScriptsSanity(const CMutableTransaction& tx)
{
    // Check input scripts for non-coinbase txs
    if (!CTransaction(tx).IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {
                return false;
            }
        }
    }
    // Check output scripts
    for (unsigned int i = 0; i < tx.vout.size(); i++) {
        if (!tx.vout[i].scriptPubKey.HasValidOps() || tx.vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE) {
            return false;
        }
    }

    return true;
}

bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
{
    if (!IsHex(hex_tx)) {
        return false;
    }

    std::vector<unsigned char> txData(ParseHex(hex_tx));

    if (try_no_witness) {
        CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
        try {
            ssData >> tx;
            if (ssData.eof() && (!try_witness || CheckTxScriptsSanity(tx))) {
                return true;
            }
        } catch (const std::exception&) {
            // Fall through.
        }
    }

    if (try_witness) {
        CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
        try {
            ssData >> tx;
            if (ssData.empty()) {
                return true;
            }
        } catch (const std::exception&) {
            // Fall through.
        }
    }

    return false;
}

bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
{
    if (!IsHex(hex_header)) return false;

    const std::vector<unsigned char> header_data{ParseHex(hex_header)};
    CDataStream ser_header(header_data, SER_NETWORK, PROTOCOL_VERSION);
    try {
        ser_header >> header;
    } catch (const std::exception&) {
        return false;
    }
    return true;
}

bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
{
    if (!IsHex(strHexBlk))
        return false;

    std::vector<unsigned char> blockData(ParseHex(strHexBlk));
    CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
    try {
        ssBlock >> block;
    }
    catch (const std::exception&) {
        return false;
    }

    return true;
}

bool ParseHashStr(const std::string& strHex, uint256& result)
{
    if ((strHex.size() != 64) || !IsHex(strHex))
        return false;

    result.SetHex(strHex);
    return true;
}

std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
{
    std::string strHex;
    if (v.isStr())
        strHex = v.getValStr();
    if (!IsHex(strHex))
        throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
    return ParseHex(strHex);
}

int ParseSighashString(const UniValue& sighash)
{
    int hash_type = SIGHASH_ALL;
    if (!sighash.isNull()) {
        static std::map<std::string, int> map_sighash_values = {
            {std::string("ALL"), int(SIGHASH_ALL)},
            {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
            {std::string("NONE"), int(SIGHASH_NONE)},
            {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
            {std::string("SINGLE"), int(SIGHASH_SINGLE)},
            {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
        };
        std::string strHashType = sighash.get_str();
        const auto& it = map_sighash_values.find(strHashType);
        if (it != map_sighash_values.end()) {
            hash_type = it->second;
        } else {
            throw std::runtime_error(strHashType + " is not a valid sighash parameter.");
        }
    }
    return hash_type;
}
<commit_msg>Include core_io.h from core_read.cpp<commit_after>// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <core_io.h>

#include <primitives/block.h>
#include <primitives/transaction.h>
#include <script/script.h>
#include <script/sign.h>
#include <serialize.h>
#include <streams.h>
#include <univalue.h>
#include <util/strencodings.h>
#include <version.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>

#include <algorithm>

CScript ParseScript(const std::string& s)
{
    CScript result;

    static std::map<std::string, opcodetype> mapOpNames;

    if (mapOpNames.empty())
    {
        for (unsigned int op = 0; op <= MAX_OPCODE; op++)
        {
            // Allow OP_RESERVED to get into mapOpNames
            if (op < OP_NOP && op != OP_RESERVED)
                continue;

            const char* name = GetOpName(static_cast<opcodetype>(op));
            if (strcmp(name, "OP_UNKNOWN") == 0)
                continue;
            std::string strName(name);
            mapOpNames[strName] = static_cast<opcodetype>(op);
            // Convenience: OP_ADD and just ADD are both recognized:
            boost::algorithm::replace_first(strName, "OP_", "");
            mapOpNames[strName] = static_cast<opcodetype>(op);
        }
    }

    std::vector<std::string> words;
    boost::algorithm::split(words, s, boost::algorithm::is_any_of(" \t\n"), boost::algorithm::token_compress_on);

    for (std::vector<std::string>::const_iterator w = words.begin(); w != words.end(); ++w)
    {
        if (w->empty())
        {
            // Empty string, ignore. (boost::split given '' will return one word)
        }
        else if (std::all_of(w->begin(), w->end(), ::IsDigit) ||
            (w->front() == '-' && w->size() > 1 && std::all_of(w->begin()+1, w->end(), ::IsDigit)))
        {
            // Number
            int64_t n = atoi64(*w);
            result << n;
        }
        else if (w->substr(0,2) == "0x" && w->size() > 2 && IsHex(std::string(w->begin()+2, w->end())))
        {
            // Raw hex data, inserted NOT pushed onto stack:
            std::vector<unsigned char> raw = ParseHex(std::string(w->begin()+2, w->end()));
            result.insert(result.end(), raw.begin(), raw.end());
        }
        else if (w->size() >= 2 && w->front() == '\'' && w->back() == '\'')
        {
            // Single-quoted string, pushed as data. NOTE: this is poor-man's
            // parsing, spaces/tabs/newlines in single-quoted strings won't work.
            std::vector<unsigned char> value(w->begin()+1, w->end()-1);
            result << value;
        }
        else if (mapOpNames.count(*w))
        {
            // opcode, e.g. OP_ADD or ADD:
            result << mapOpNames[*w];
        }
        else
        {
            throw std::runtime_error("script parse error");
        }
    }

    return result;
}

// Check that all of the input and output scripts of a transaction contains valid opcodes
static bool CheckTxScriptsSanity(const CMutableTransaction& tx)
{
    // Check input scripts for non-coinbase txs
    if (!CTransaction(tx).IsCoinBase()) {
        for (unsigned int i = 0; i < tx.vin.size(); i++) {
            if (!tx.vin[i].scriptSig.HasValidOps() || tx.vin[i].scriptSig.size() > MAX_SCRIPT_SIZE) {
                return false;
            }
        }
    }
    // Check output scripts
    for (unsigned int i = 0; i < tx.vout.size(); i++) {
        if (!tx.vout[i].scriptPubKey.HasValidOps() || tx.vout[i].scriptPubKey.size() > MAX_SCRIPT_SIZE) {
            return false;
        }
    }

    return true;
}

bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness, bool try_witness)
{
    if (!IsHex(hex_tx)) {
        return false;
    }

    std::vector<unsigned char> txData(ParseHex(hex_tx));

    if (try_no_witness) {
        CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
        try {
            ssData >> tx;
            if (ssData.eof() && (!try_witness || CheckTxScriptsSanity(tx))) {
                return true;
            }
        } catch (const std::exception&) {
            // Fall through.
        }
    }

    if (try_witness) {
        CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
        try {
            ssData >> tx;
            if (ssData.empty()) {
                return true;
            }
        } catch (const std::exception&) {
            // Fall through.
        }
    }

    return false;
}

bool DecodeHexBlockHeader(CBlockHeader& header, const std::string& hex_header)
{
    if (!IsHex(hex_header)) return false;

    const std::vector<unsigned char> header_data{ParseHex(hex_header)};
    CDataStream ser_header(header_data, SER_NETWORK, PROTOCOL_VERSION);
    try {
        ser_header >> header;
    } catch (const std::exception&) {
        return false;
    }
    return true;
}

bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
{
    if (!IsHex(strHexBlk))
        return false;

    std::vector<unsigned char> blockData(ParseHex(strHexBlk));
    CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
    try {
        ssBlock >> block;
    }
    catch (const std::exception&) {
        return false;
    }

    return true;
}

bool ParseHashStr(const std::string& strHex, uint256& result)
{
    if ((strHex.size() != 64) || !IsHex(strHex))
        return false;

    result.SetHex(strHex);
    return true;
}

std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)
{
    std::string strHex;
    if (v.isStr())
        strHex = v.getValStr();
    if (!IsHex(strHex))
        throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
    return ParseHex(strHex);
}

int ParseSighashString(const UniValue& sighash)
{
    int hash_type = SIGHASH_ALL;
    if (!sighash.isNull()) {
        static std::map<std::string, int> map_sighash_values = {
            {std::string("ALL"), int(SIGHASH_ALL)},
            {std::string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)},
            {std::string("NONE"), int(SIGHASH_NONE)},
            {std::string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)},
            {std::string("SINGLE"), int(SIGHASH_SINGLE)},
            {std::string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)},
        };
        std::string strHashType = sighash.get_str();
        const auto& it = map_sighash_values.find(strHashType);
        if (it != map_sighash_values.end()) {
            hash_type = it->second;
        } else {
            throw std::runtime_error(strHashType + " is not a valid sighash parameter.");
        }
    }
    return hash_type;
}
<|endoftext|>


<commit_before>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "cpu.hh"
#include "gc.hh"
#include "percpu.hh"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "uwq.hh"
#include "vm.hh"
#include "kalloc.hh"
#include "bits.hh"
extern "C" {
#include "kern_c.h"
}

bool
uwq_trywork(void)
{
  // Returning true means uwq added a thread to the run queue

  u64 i, k;

  // A "random" victim CPU
  k = rdtsc();
  for (i = 0; i < NCPU; i++) {
    u64 j = (i+k) % NCPU;

    if (j == mycpuid())
      continue;
    struct cpu *c = &cpus[j];

    // The gc_epoch is for p and uwq
    scoped_gc_epoch xgc();
    barrier();

    struct proc *p = c->proc;
    if (p == nullptr)
      continue;
    uwq* uwq = p->uwq;
    if (uwq == nullptr)
      continue;

    if (uwq->haswork()) {
      if (uwq->tryworker())
        return true;
      break;
    }
  }

  return false;
}

long
sys_wqwait(void)
{
  uwq_worker* w = myproc()->worker;
  if (w == nullptr)
    return -1;

  return w->wait();
}

//
// uwq_worker
//
uwq_worker::uwq_worker(uwq* u, proc* p)
  : uwq_(u), proc_(p), running_(false)
{
  initlock(&lock_, "worker_lock", 0);
  initcondvar(&cv_, "worker_cv");
}

void
uwq_worker::exit(void)
{
  if (--uwq_->uref_ == 0)
    gc_delayed(uwq_);
  release(&lock_);
  delete this;
  ::exit();
}

long
uwq_worker::wait(void)
{
  acquire(&lock_);
  if (!uwq_->valid())
    this->exit();

  running_ = false;
  cv_sleep(&cv_, &lock_);

  if (!uwq_->valid())
    this->exit();
  release(&lock_);
  return 0;
}

//
// uwq
//
uwq*
uwq::alloc(vmap* vmap, filetable *ftable)
{
  uwq_ipcbuf* ipc;
  uwq* u;

  ipc = (uwq_ipcbuf*) ksalloc(slab_userwq);
  if (ipc == nullptr)
    return nullptr;

  ftable->incref();
  vmap->incref();

  u = new uwq(vmap, ftable, ipc);
  if (u == nullptr) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    return nullptr;
  }

  if (mapkva(vmap->pml4, (char*)ipc, USERWQ, USERWQSIZE)) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    u->dec();
    return nullptr;
  }

  return u;
}

uwq::uwq(vmap* vmap, filetable* ftable, uwq_ipcbuf* ipc)
  : rcu_freed("uwq"),
    vmap_(vmap), ftable_(ftable), ipc_(ipc),
    uentry_(0), ustack_(UWQSTACK), uref_(0)
{
  ftable_->incref();
  vmap_->incref();
  for (int i = 0; i < NCPU; i++)
    ipc_->len[i].v_ = 0;

  initlock(&lock_, "uwq_lock", 0);

  for (int i = 0; i < NWORKERS; i++)
    worker_[i].store(nullptr);
}

uwq::~uwq(void)
{
  if (ipc_ != nullptr)
    ksfree(slab_userwq, ipc_);
  vmap_->decref();
  ftable_->decref();
}

bool
uwq::haswork(void) const
{
  if (ipc_ == nullptr)
    return false;

  for (int i = 0; i < NCPU; i++) {
    if (ipc_->len[i].v_ > 0) {
      return true;
    }
  }
  return false;
}

bool
uwq::tryworker(void)
{
  if (!valid())
    return false;

  // Try to start a worker thread
  scoped_acquire lock0(&lock_);

  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] == nullptr)
      continue;

    uwq_worker *w = worker_[i];
    if (w->running_)
      continue;
    else {
      scoped_acquire lock1(&w->lock_);
      proc* p = w->proc_;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      release(&p->lock);

      w->running_ = true;
      cv_wakeup(&w->cv_);
      return true;
    }
  }
  lock0.release();

again:
  u64 uref = uref_.load();
  if (uref < ipc_->maxworkers) {
    if (!cmpxch(&uref_, uref, uref+1))
      goto again;
    // Guaranteed to have  slot in worker_

    proc* p = allocworker();
    if (p != nullptr) {
      uwq_worker* w = new uwq_worker(this, p);
      assert(w != nullptr);

      ++uref_;
      p->worker = w;
      w->running_ = true;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      addrun(p);
      release(&p->lock);

      for (int i = 0; i < NWORKERS; i++) {
        if (worker_[i] == nullptr)
          if (cmpxch(&worker_[i], (uwq_worker*)nullptr, w))
            return true;
      }
      panic("uwq::tryworker: oops");
    }
  }

  return false;
}

void
uwq::finish(void)
{
  bool gcnow = true;

  scoped_acquire lock0(&lock_);
  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] != nullptr) {
      uwq_worker* w = worker_[i];
      gcnow = false;
      acquire(&w->lock_);
      cv_wakeup(&w->cv_);
      release(&w->lock_);
    }
  }

  if (gcnow)
    gc_delayed(this);
}

void
uwq::onzero() const
{
  uwq *u = (uwq*)this;
  u->finish();
}

void
uwq::setuentry(uptr uentry)
{
  uentry_ = uentry;
}

proc*
uwq::allocworker(void)
{
  uptr uentry = uentry_;

  if (uentry == 0)
    return nullptr;

  proc* p = proc::alloc();
  if (p == nullptr)
    return nullptr;
  safestrcpy(p->name, "uwq_worker", sizeof(p->name));

  // finishproc will drop these refs
  vmap_->incref();
  ftable_->incref();

  p->vmap = vmap_;
  p->ftable = ftable_;

  struct vmnode *vmn;
  if ((vmn = new vmnode(USTACKPAGES)) == nullptr) {
    finishproc(p);
    return nullptr;
  }

  // Include a bumper page
  uptr ustack = ustack_.fetch_add((USTACKPAGES*PGSIZE)+PGSIZE);
  uptr stacktop = ustack + (USTACKPAGES*PGSIZE);
  if (vmap_->insert(vmn, ustack, 1) < 0) {
    delete vmn;
    finishproc(p);
    return nullptr;
  }

  p->tf->rsp = stacktop - 8;
  p->tf->rip = uentry;
  p->tf->cs = UCSEG | 0x3;
  p->tf->ds = UDSEG | 0x3;
  p->tf->ss = p->tf->ds;
  p->tf->rflags = FL_IF;

  return p;
}
<commit_msg>Oops, that wasn't right either..<commit_after>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "cpu.hh"
#include "gc.hh"
#include "percpu.hh"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "uwq.hh"
#include "vm.hh"
#include "kalloc.hh"
#include "bits.hh"
extern "C" {
#include "kern_c.h"
}

bool
uwq_trywork(void)
{
  // Returning true means uwq added a thread to the run queue

  u64 i, k;

  // A "random" victim CPU
  k = rdtsc();
  for (i = 0; i < NCPU; i++) {
    u64 j = (i+k) % NCPU;

    if (j == mycpuid())
      continue;
    struct cpu *c = &cpus[j];

    // The gc_epoch is for p and uwq
    scoped_gc_epoch xgc();
    barrier();

    struct proc *p = c->proc;
    if (p == nullptr)
      continue;
    uwq* uwq = p->uwq;
    if (uwq == nullptr)
      continue;

    if (uwq->haswork()) {
      if (uwq->tryworker())
        return true;
      break;
    }
  }

  return false;
}

long
sys_wqwait(void)
{
  uwq_worker* w = myproc()->worker;
  if (w == nullptr)
    return -1;

  return w->wait();
}

//
// uwq_worker
//
uwq_worker::uwq_worker(uwq* u, proc* p)
  : uwq_(u), proc_(p), running_(false)
{
  initlock(&lock_, "worker_lock", 0);
  initcondvar(&cv_, "worker_cv");
}

void
uwq_worker::exit(void)
{
  if (--uwq_->uref_ == 0)
    gc_delayed(uwq_);
  release(&lock_);
  delete this;
  ::exit();
}

long
uwq_worker::wait(void)
{
  acquire(&lock_);
  if (!uwq_->valid())
    this->exit();

  running_ = false;
  cv_sleep(&cv_, &lock_);

  if (!uwq_->valid())
    this->exit();
  release(&lock_);
  return 0;
}

//
// uwq
//
uwq*
uwq::alloc(vmap* vmap, filetable *ftable)
{
  uwq_ipcbuf* ipc;
  uwq* u;

  ipc = (uwq_ipcbuf*) ksalloc(slab_userwq);
  if (ipc == nullptr)
    return nullptr;

  ftable->incref();
  vmap->incref();

  u = new uwq(vmap, ftable, ipc);
  if (u == nullptr) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    return nullptr;
  }

  if (mapkva(vmap->pml4, (char*)ipc, USERWQ, USERWQSIZE)) {
    ksfree(slab_userwq, ipc);
    u->dec();
    return nullptr;
  }

  return u;
}

uwq::uwq(vmap* vmap, filetable* ftable, uwq_ipcbuf* ipc)
  : rcu_freed("uwq"),
    vmap_(vmap), ftable_(ftable), ipc_(ipc),
    uentry_(0), ustack_(UWQSTACK), uref_(0)
{
  for (int i = 0; i < NCPU; i++)
    ipc_->len[i].v_ = 0;

  initlock(&lock_, "uwq_lock", 0);

  for (int i = 0; i < NWORKERS; i++)
    worker_[i].store(nullptr);
}

uwq::~uwq(void)
{
  if (ipc_ != nullptr)
    ksfree(slab_userwq, ipc_);
  vmap_->decref();
  ftable_->decref();
}

bool
uwq::haswork(void) const
{
  if (ipc_ == nullptr)
    return false;

  for (int i = 0; i < NCPU; i++) {
    if (ipc_->len[i].v_ > 0) {
      return true;
    }
  }
  return false;
}

bool
uwq::tryworker(void)
{
  if (!valid())
    return false;

  // Try to start a worker thread
  scoped_acquire lock0(&lock_);

  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] == nullptr)
      continue;

    uwq_worker *w = worker_[i];
    if (w->running_)
      continue;
    else {
      scoped_acquire lock1(&w->lock_);
      proc* p = w->proc_;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      release(&p->lock);

      w->running_ = true;
      cv_wakeup(&w->cv_);
      return true;
    }
  }
  lock0.release();

again:
  u64 uref = uref_.load();
  if (uref < ipc_->maxworkers) {
    if (!cmpxch(&uref_, uref, uref+1))
      goto again;
    // Guaranteed to have  slot in worker_

    proc* p = allocworker();
    if (p != nullptr) {
      uwq_worker* w = new uwq_worker(this, p);
      assert(w != nullptr);

      ++uref_;
      p->worker = w;
      w->running_ = true;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      addrun(p);
      release(&p->lock);

      for (int i = 0; i < NWORKERS; i++) {
        if (worker_[i] == nullptr)
          if (cmpxch(&worker_[i], (uwq_worker*)nullptr, w))
            return true;
      }
      panic("uwq::tryworker: oops");
    }
  }

  return false;
}

void
uwq::finish(void)
{
  bool gcnow = true;

  scoped_acquire lock0(&lock_);
  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] != nullptr) {
      uwq_worker* w = worker_[i];
      gcnow = false;
      acquire(&w->lock_);
      cv_wakeup(&w->cv_);
      release(&w->lock_);
    }
  }

  if (gcnow)
    gc_delayed(this);
}

void
uwq::onzero() const
{
  uwq *u = (uwq*)this;
  u->finish();
}

void
uwq::setuentry(uptr uentry)
{
  uentry_ = uentry;
}

proc*
uwq::allocworker(void)
{
  uptr uentry = uentry_;

  if (uentry == 0)
    return nullptr;

  proc* p = proc::alloc();
  if (p == nullptr)
    return nullptr;
  safestrcpy(p->name, "uwq_worker", sizeof(p->name));

  // finishproc will drop these refs
  vmap_->incref();
  ftable_->incref();

  p->vmap = vmap_;
  p->ftable = ftable_;

  struct vmnode *vmn;
  if ((vmn = new vmnode(USTACKPAGES)) == nullptr) {
    finishproc(p);
    return nullptr;
  }

  // Include a bumper page
  uptr ustack = ustack_.fetch_add((USTACKPAGES*PGSIZE)+PGSIZE);
  uptr stacktop = ustack + (USTACKPAGES*PGSIZE);
  if (vmap_->insert(vmn, ustack, 1) < 0) {
    delete vmn;
    finishproc(p);
    return nullptr;
  }

  p->tf->rsp = stacktop - 8;
  p->tf->rip = uentry;
  p->tf->cs = UCSEG | 0x3;
  p->tf->ds = UDSEG | 0x3;
  p->tf->ss = p->tf->ds;
  p->tf->rflags = FL_IF;

  return p;
}
<|endoftext|>