<commit_before>#include <iostream>
#include <string>
#include <vector>

using namespace std;

//util classes
struct Input {
	int r, c, l, h;
	vector<vector<bool>> tomatoes;
};

struct Slice {
	int r1, c1, r2, c2;
};

struct Output {
	vector<Slice> slices;
};

bool checkSlice(Input &input, Slice &s)
{
	bool t = false;
	bool f = false;
	for (int j = s.c1; j <= s.c2; j++)
	{
		if (input.tomatoes[s.r1][j])
			t = true;
		else
			f = true;

		if (t == true && f == true)
			return true;
	}
	return false;
}

void solveSimpleHorizontal(Input& input, Output& output) {
	for (int i = 0; i < input.r; i++)
	{
		for (int j = 0; j < input.c; j += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = i;
			s.c2 = min(j+input.h-1, input.c-1);
			if (checkSlice(input, s))
				output.slices.push_back(s);
		}
	}
}

void solveSimpleVertical(Input& input, Output& output) {
	for (int j = 0; j < input.c; j++)
	{
		for (int i = 0; i < input.r; i += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = min(i+input.h-1, input.r-1);
			s.c2 = j;
			if (checkSlice(input, s))
				output.slices.push_back(s);
		}
	}
}

int add_slice(const vector<bool> &a, int l, int r)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	if (cnt1 >= l && cnt2 >= l)
		return r-l+1;
	return 0;
}

void solve_row(const vector<bool> &a, int row_num, int n, int l, int h, vector<Slice> &ans)	{
	vector<int> d(n,0), prev(n,0);

	for (int i = 0; i < n; i++)
		for (int j = 2*l; j <= h; j++)
			 if (i-j+1 >= 0)
			 {
			 	int temp = add_slice(a,i-j+1,i);
			 	if (d[i] < d[i-j+1] + temp)
				{
			 		d[i] = d[i-j+1] + temp;
					prev[i] = i-j+1;
			 	}
			}

	int i_max = 0;
	for (int i = 0; i < n; i++)
		if (d[i] > d[i_max])
			i_max = i;

	Slice c;
	c.r1 = c.r2 = row_num;

	for (int i = i_max; i > 0; i--)
	{
		c.c1 = prev[i]; c.c2 = i;
		i = prev[i]-1;
		ans.push_back(c);
	}
}

void solveDP(Input& input, Output& output) {

	for (int i = 0; i < input.r; i++)
		solve_row(input.tomatoes[i],i,input.c,input.l,input.h,output.slices);
}

//input/output code
int main(int argc, char* argv[]) {
	ios::sync_with_stdio(false);

	//read input
	Input input;
	cin >> input.r >> input.c >> input.l >> input.h;
	for(int i = 0; i < input.r; i++) {
		vector<bool> row(input.c);
		for(int j = 0; j < input.c; j++) {
			char cell;
			cin >> cell;
			row[j] = cell == 'T';
		}
		input.tomatoes.push_back(row);
		//TODO do we read line breaks?
	}

	//read command line args
	string algorithm = "simplehorizontal";
	if(argc > 2) {
		algorithm = argv[1];
	}

	//solve problem
	Output output;
	cerr << "using algorithm " << algorithm << endl;
	if(algorithm == "simplehorizontal") {
		solveSimpleHorizontal(input, output);
	}
	else if(algorithm == "simplevertical") {
		solveSimpleVertical(input, output);
	}
	else if(algorithm == "dp") {
		solveDP(input, output);
	}
	else {
		cerr << "unknown algorithm" << endl;
		return 1;
	}

	//print output
	cout << output.slices.size() << endl;
	for(Slice slice: output.slices) {
		cout << slice.r1 << ' ' << slice.c1 << ' ' << slice.r2 << ' ' << slice.c2 << endl;
	}
};
<commit_msg>Splitted checkSlice function for horizontal and vertical version<commit_after>#include <iostream>
#include <string>
#include <vector>

using namespace std;

//util classes
struct Input {
	int r, c, l, h;
	vector<vector<bool>> tomatoes;
};

struct Slice {
	int r1, c1, r2, c2;
};

struct Output {
	vector<Slice> slices;
};

bool checkSliceHorizontal(Input &input, Slice &s)
{
	bool t = false;
	bool f = false;
	for (int j = s.c1; j <= s.c2; j++)
	{
		if (input.tomatoes[s.r1][j])
			t = true;
		else
			f = true;

		if (t == true && f == true)
			return true;
	}
	return false;
}

bool checkSliceVertical(Input &input, Slice &s)
{
	bool t = false;
	bool f = false;
	for (int i = s.r1; i <= s.r2; i++)
	{
		if (input.tomatoes[i][s.c1])
			t = true;
		else
			f = true;

		if (t == true && f == true)
			return true;
	}
	return false;
}

void solveSimpleHorizontal(Input& input, Output& output) {
	for (int i = 0; i < input.r; i++)
	{
		for (int j = 0; j < input.c; j += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = i;
			s.c2 = min(j+input.h-1, input.c-1);
			if (checkSliceHorizontal(input, s))
				output.slices.push_back(s);
		}
	}
}

void solveSimpleVertical(Input& input, Output& output) {
	for (int j = 0; j < input.c; j++)
	{
		for (int i = 0; i < input.r; i += input.h)
		{
			Slice s;
			s.r1 = i;
			s.c1 = j;
			s.r2 = min(i+input.h-1, input.r-1);
			s.c2 = j;
			if (checkSliceVertical(input, s))
				output.slices.push_back(s);
		}
	}
}

int add_slice(const vector<bool> &a, int l, int r)	{
	int cnt1 = 0, cnt2 = 0;
	for (int i = l; i <= r; i++)
		if (a[i])
			cnt1++;
		else
			cnt2++;

	if (cnt1 >= l && cnt2 >= l)
		return r-l+1;
	return 0;
}

void solve_row(const vector<bool> &a, int row_num, int n, int l, int h, vector<Slice> &ans)	{
	vector<int> d(n,0), prev(n,0);

	for (int i = 0; i < n; i++)
		for (int j = 2*l; j <= h; j++)
			 if (i-j+1 >= 0)
			 {
			 	int temp = add_slice(a,i-j+1,i);
			 	if (d[i] < d[i-j+1] + temp)
				{
			 		d[i] = d[i-j+1] + temp;
					prev[i] = i-j+1;
			 	}
			}

	int i_max = 0;
	for (int i = 0; i < n; i++)
		if (d[i] > d[i_max])
			i_max = i;

	Slice c;
	c.r1 = c.r2 = row_num;

	for (int i = i_max; i > 0; i--)
	{
		c.c1 = prev[i]; c.c2 = i;
		i = prev[i]-1;
		ans.push_back(c);
	}
}

void solveDP(Input& input, Output& output) {

	for (int i = 0; i < input.r; i++)
		solve_row(input.tomatoes[i],i,input.c,input.l,input.h,output.slices);
}

//input/output code
int main(int argc, char* argv[]) {
	ios::sync_with_stdio(false);

	//read input
	Input input;
	cin >> input.r >> input.c >> input.l >> input.h;
	for(int i = 0; i < input.r; i++) {
		vector<bool> row(input.c);
		for(int j = 0; j < input.c; j++) {
			char cell;
			cin >> cell;
			row[j] = cell == 'T';
		}
		input.tomatoes.push_back(row);
		//TODO do we read line breaks?
	}

	//read command line args
	string algorithm = "simplehorizontal";
	if(argc > 2) {
		algorithm = argv[1];
	}

	//solve problem
	Output output;
	cerr << "using algorithm " << algorithm << endl;
	if(algorithm == "simplehorizontal") {
		solveSimpleHorizontal(input, output);
	}
	else if(algorithm == "simplevertical") {
		solveSimpleVertical(input, output);
	}
	else if(algorithm == "dp") {
		solveDP(input, output);
	}
	else {
		cerr << "unknown algorithm" << endl;
		return 1;
	}

	//print output
	cout << output.slices.size() << endl;
	for(Slice slice: output.slices) {
		cout << slice.r1 << ' ' << slice.c1 << ' ' << slice.r2 << ' ' << slice.c2 << endl;
	}
};
<|endoftext|>


<commit_before>#include "Common/HighQueuePch.h"
#define BOOST_TEST_NO_MAIN HighQueuePerformanceTest
#include <boost/test/unit_test.hpp>

#include <HighQueue/Producer.h>
#include <HighQueue/Consumer.h>
#include <Common/Stopwatch.h>
#include <HQPerformance/TestMessage.h>

using namespace HighQueue;
typedef TestMessage<20> ActualMessage;

namespace
{
    volatile std::atomic<uint32_t> threadsReady;
    volatile bool producerGo = false;

    void producerFunction(Connection & connection, uint32_t producerNumber, uint64_t messageCount, bool solo)
    {
        Producer producer(connection, solo);
        HighQueue::Message producerMessage;
        if(!connection.allocate(producerMessage))
        {
            std::cerr << "Failed to allocate message for producer Number " << producerNumber << std::endl;
            return;
        }

        ++threadsReady;
        while(!producerGo)
        {
            std::this_thread::yield();
        }

        for(uint32_t messageNumber = 0; messageNumber < messageCount; ++messageNumber)
        {
            auto testMessage = producerMessage.construct<ActualMessage>(producerNumber, messageNumber);
            producer.publish(producerMessage);
        }
    }
}

#define DISABLE_MultithreadMessagePassingPerformancex
#ifdef DISABLE_MultithreadMessagePassingPerformance
#pragma message ("DISABLE_MultithreadMessagePassingPerformance")
#else // DISABLE_MultithreadMessagePassingPerformance
BOOST_AUTO_TEST_CASE(testMultithreadMessagePassingPerformance)
{
    static const size_t entryCount = 100000;
    static const size_t messageSize = sizeof(ActualMessage);

    static const uint64_t targetMessageCount = 1000000 * 100; // runs about 5 to 10 seconds in release/optimized build
    static const size_t producerLimit = 2;//10; // running on 8 core system.  Once we go over 7 producers it slows down.  That's one thing we want to see.
    static const size_t consumerLimit = 1;  // Just for documentation
    static const size_t messageCount = entryCount + consumerLimit +  producerLimit;

    static const size_t spinCount = 0;
    static const size_t yieldCount = ConsumerWaitStrategy::FOREVER;

    ConsumerWaitStrategy strategy(spinCount, yieldCount);
    CreationParameters parameters(strategy, entryCount, messageSize, messageCount);
    Connection connection;
    connection.createLocal("LocalIv", parameters);

    Consumer consumer(connection);
    HighQueue::Message consumerMessage;
    BOOST_REQUIRE(connection.allocate(consumerMessage));

    for(size_t producerCount = 1; producerCount < producerLimit; ++producerCount)
    {
        std::cerr << "Test " << producerCount << " producer";

        std::vector<std::thread> producerThreads;
        std::vector<uint64_t> nextMessage;

        threadsReady = 0;
        producerGo = false;
        size_t perProducer = targetMessageCount / producerCount;
        size_t actualMessageCount = perProducer * producerCount;

        for(uint32_t nTh = 0; nTh < producerCount; ++nTh)
        {
            nextMessage.emplace_back(0u);
            producerThreads.emplace_back(
                std::bind(producerFunction, std::ref(connection), nTh, perProducer, producerCount == 1));
        }
        std::this_thread::yield();

        while(threadsReady < producerCount)
        {
            std::this_thread::yield();
        }

        Stopwatch timer;
        producerGo = true;

        for(uint64_t messageNumber = 0; messageNumber < actualMessageCount; ++messageNumber)
        {
            consumer.getNext(consumerMessage);
            auto testMessage = consumerMessage.get<ActualMessage>();
            testMessage->touch();
            auto & msgNumber = nextMessage[testMessage->producerNumber()];
            if(msgNumber != testMessage->messageNumber())
            {
                // the if avoids the performance hit of BOOST_CHECK_EQUAL unless it's needed.
                BOOST_CHECK_EQUAL(messageNumber, testMessage->messageNumber());
            }
            ++ msgNumber;
        }

        auto lapse = timer.nanoseconds();

        // sometimes we synchronize thread shut down.
        producerGo = false;

        for(size_t nTh = 0; nTh < producerCount; ++nTh)
        {
            producerThreads[nTh].join();
        }

        auto messageBytes = sizeof(ActualMessage);
        auto messageBits = sizeof(ActualMessage) * 8;
        std::cout << " Passed " << actualMessageCount << ' ' << messageBytes << " byte messages in "
            << std::setprecision(9) << double(lapse) / double(Stopwatch::nanosecondsPerSecond) << " seconds.  "
            << lapse / actualMessageCount << " nsec./message "
            << std::setprecision(3) << double(actualMessageCount) / double(lapse) << " GMsg/second "
            << std::setprecision(3) << double(actualMessageCount * messageBytes) / double(lapse) << " GByte/second "
            << std::setprecision(3) << double(actualMessageCount * messageBits) / double(lapse) << " GBit/second."
            << std::endl;
    }
}
#endif // DISABLE_MultithreadMessagePassingPerformance
<commit_msg>Re-enable multithread test<commit_after>#include "Common/HighQueuePch.h"
#define BOOST_TEST_NO_MAIN HighQueuePerformanceTest
#include <boost/test/unit_test.hpp>

#include <HighQueue/Producer.h>
#include <HighQueue/Consumer.h>
#include <Common/Stopwatch.h>
#include <HQPerformance/TestMessage.h>

using namespace HighQueue;
typedef TestMessage<20> ActualMessage;

namespace
{
    volatile std::atomic<uint32_t> threadsReady;
    volatile bool producerGo = false;

    void producerFunction(Connection & connection, uint32_t producerNumber, uint64_t messageCount, bool solo)
    {
        Producer producer(connection, solo);
        HighQueue::Message producerMessage;
        if(!connection.allocate(producerMessage))
        {
            std::cerr << "Failed to allocate message for producer Number " << producerNumber << std::endl;
            return;
        }

        ++threadsReady;
        while(!producerGo)
        {
            std::this_thread::yield();
        }

        for(uint32_t messageNumber = 0; messageNumber < messageCount; ++messageNumber)
        {
            auto testMessage = producerMessage.construct<ActualMessage>(producerNumber, messageNumber);
            producer.publish(producerMessage);
        }
    }
}

#define DISABLE_MultithreadMessagePassingPerformancex
#ifdef DISABLE_MultithreadMessagePassingPerformance
#pragma message ("DISABLE_MultithreadMessagePassingPerformance")
#else // DISABLE_MultithreadMessagePassingPerformance
BOOST_AUTO_TEST_CASE(testMultithreadMessagePassingPerformance)
{
    static const size_t entryCount = 100000;
    static const size_t messageSize = sizeof(ActualMessage);

    static const uint64_t targetMessageCount = 1000000 * 100; // runs about 5 to 10 seconds in release/optimized build
    static const size_t producerLimit = 8; // running on 8 core system.  Once we go over 7 producers it slows down.  That's one thing we want to see.
    static const size_t consumerLimit = 1;  // Just for documentation
    static const size_t messageCount = entryCount + consumerLimit +  producerLimit;

    static const size_t spinCount = 0;
    static const size_t yieldCount = ConsumerWaitStrategy::FOREVER;

    ConsumerWaitStrategy strategy(spinCount, yieldCount);
    CreationParameters parameters(strategy, entryCount, messageSize, messageCount);
    Connection connection;
    connection.createLocal("LocalIv", parameters);

    Consumer consumer(connection);
    HighQueue::Message consumerMessage;
    BOOST_REQUIRE(connection.allocate(consumerMessage));

    for(size_t producerCount = 1; producerCount <= producerLimit; ++producerCount)
    {
        std::cerr << "Test " << producerCount << " producer";

        std::vector<std::thread> producerThreads;
        std::vector<uint64_t> nextMessage;

        threadsReady = 0;
        producerGo = false;
        size_t perProducer = targetMessageCount / producerCount;
        size_t actualMessageCount = perProducer * producerCount;

        for(uint32_t nTh = 0; nTh < producerCount; ++nTh)
        {
            nextMessage.emplace_back(0u);
            producerThreads.emplace_back(
                std::bind(producerFunction, std::ref(connection), nTh, perProducer, producerCount == 1));
        }
        std::this_thread::yield();

        while(threadsReady < producerCount)
        {
            std::this_thread::yield();
        }

        Stopwatch timer;
        producerGo = true;

        for(uint64_t messageNumber = 0; messageNumber < actualMessageCount; ++messageNumber)
        {
            consumer.getNext(consumerMessage);
            auto testMessage = consumerMessage.get<ActualMessage>();
            testMessage->touch();
            auto & msgNumber = nextMessage[testMessage->producerNumber()];
            if(msgNumber != testMessage->messageNumber())
            {
                // the if avoids the performance hit of BOOST_CHECK_EQUAL unless it's needed.
                BOOST_CHECK_EQUAL(messageNumber, testMessage->messageNumber());
            }
            ++ msgNumber;
        }

        auto lapse = timer.nanoseconds();

        // sometimes we synchronize thread shut down.
        producerGo = false;

        for(size_t nTh = 0; nTh < producerCount; ++nTh)
        {
            producerThreads[nTh].join();
        }

        auto messageBytes = sizeof(ActualMessage);
        auto messageBits = sizeof(ActualMessage) * 8;
        std::cout << " Passed " << actualMessageCount << ' ' << messageBytes << " byte messages in "
            << std::setprecision(9) << double(lapse) / double(Stopwatch::nanosecondsPerSecond) << " seconds.  "
            << lapse / actualMessageCount << " nsec./message "
            << std::setprecision(3) << double(actualMessageCount) / double(lapse) << " GMsg/second "
            << std::setprecision(3) << double(actualMessageCount * messageBytes) / double(lapse) << " GByte/second "
            << std::setprecision(3) << double(actualMessageCount * messageBits) / double(lapse) << " GBit/second."
            << std::endl;
    }
}
#endif // DISABLE_MultithreadMessagePassingPerformance
<|endoftext|>


<commit_before>#include "vm.hpp"
#include "vm/object_utils.hpp"

#include "builtin/array.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/tuple.hpp"
#include "builtin/class.hpp"
#include "objectmemory.hpp"
#include "primitives.hpp"

#include <iostream>

/* Implementation certain Array methods. These methods are just
 * the ones the VM requires, not the entire set of all Array methods.
 * This includes methods required to implement certain Array
 * primitives. */

namespace rubinius {

  void Array::init(STATE) {
    GO(array).set(state->new_class("Array", G(object)));
    G(array)->set_object_type(state, ArrayType);

    native_int wordsize = as<Fixnum>(
        G(rubinius)->get_const(state, "WORDSIZE"))->to_native();
    size_t maxsize = ((size_t)::exp2(wordsize)) / (wordsize/8U);
    G(array)->set_const(state, "MAX_SIZE", Fixnum::from(maxsize));
  }

  size_t Array::size() {
    return total_->to_native();
  }

  Array* Array::create(STATE, size_t idx) {
    Array* ary;
    ary = state->new_object<Array>(G(array));

    ary->setup(state, idx);

    return ary;
  }

  // 'self' is passed in automatically by the primitive glue
  Array* Array::allocate(STATE, Object* self) {
    Array* ary = Array::create(state, 0U);
    ary->klass(state, (Class*)self);
    return ary;
  }

  Array* Array::from_tuple(STATE, Tuple* tup) {
    size_t length = tup->num_fields();
    Array* ary = Array::create(state, length);
    ary->tuple_->copy_from(state, tup,
			   Fixnum::from(0), Fixnum::from(length),
			   Fixnum::from(0));
    ary->total(state, Fixnum::from(length));
    return ary;
  }

  void Array::setup(STATE, size_t size) {
    this->tuple(state, Tuple::create(state, size));
    this->start(state, Fixnum::from(0));
    this->total(state, Fixnum::from(0));
  }

  // NOTE: We don't use Primitives::failure() here because the wrapper
  // code makes sure we're only called when the arity and type are correct.
  // Thus we know that this is a simple a[n] case only, which we can
  // fully handle.
  Object* Array::aref(STATE, Fixnum* idx) {
    native_int index = idx->to_native();
    const native_int start = start_->to_native();
    const native_int total = start + total_->to_native();

    // Handle negative indexes
    if(index < 0) {
      index += total;
    } else {
      index += start;
    }

    // Off either end, return nil
    if(index >= total || index < start) return Qnil;

    return tuple_->at(state, index);
  }

  Object* Array::aset(STATE, Fixnum* idx, Object* val) {
    native_int index = idx->to_native();

    if(index < 0) {
      return Primitives::failure();
    }

    return this->set(state, index, val);
  }

  Object* Array::get(STATE, size_t idx) {
    if(idx >= (size_t)total_->to_native()) {
      return Qnil;
    }

    idx += start_->to_native();

    return tuple_->at(state, idx);
  }

  Object* Array::set(STATE, size_t idx, Object* val) {
    size_t tuple_size = tuple_->num_fields();
    size_t oidx = idx;
    idx += start_->to_native();

    if(idx >= tuple_size) {
      // Uses the same algo as 1.8 to resize the tuple
      size_t new_size = tuple_size / 2;
      if(new_size < 3) {
        new_size = 3;
      }

      Tuple* nt = Tuple::create(state, new_size+idx);
      nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
      tuple(state, nt);
      start(state, Fixnum::from(0));
      idx = oidx;
    }

    tuple_->put(state, idx, val);
    if((size_t)total_->to_native() <= oidx) {
      total(state, Fixnum::from(oidx+1));
    }
    return val;
  }

  void Array::unshift(STATE, Object* val) {
    size_t new_size = total_->to_native() + 1;
    size_t lend = start_->to_native();

    if(lend > 0) {
      tuple_->put(state, lend-1, val);
      start(state, Fixnum::from(lend-1));
      total(state, Fixnum::from(new_size));
    } else {
      Tuple* nt = Tuple::create(state, new_size);
      nt->copy_from(state, tuple_, start_, total_,
		    Fixnum::from(1));
      nt->put(state, 0, val);

      total(state, Fixnum::from(new_size));
      start(state, Fixnum::from(0));
      tuple(state, nt);
    }
  }

  Object* Array::shift(STATE) {
    size_t cnt = total_->to_native();

    if(cnt == 0) return Qnil;
    Object* obj = get(state, 0);
    set(state, 0, Qnil);
    start(state, Fixnum::from(start_->to_native() + 1));
    total(state, Fixnum::from(cnt - 1));
    return obj;
  }

  Object* Array::append(STATE, Object* val) {
    set(state, (size_t)total_->to_native(), val);
    return val;
  }

  bool Array::includes_p(STATE, Object* val) {
    size_t cnt = total_->to_native();

    for(size_t i = 0; i < cnt; i++) {
      if(get(state, i) == val) return true;
    }

    return false;
  }

  Object* Array::pop(STATE) {
    size_t cnt = total_->to_native();

    if(cnt == 0) return Qnil;
    Object *obj = get(state, cnt - 1);
    set(state, cnt-1, Qnil);
    total(state, Fixnum::from(cnt - 1));
    return obj;
  }

  void Array::Info::show(STATE, Object* self, int level) {
    Array* ary = as<Array>(self);
    size_t size = ary->size();
    size_t stop = size < 5 ? size : 5;

    if(size == 0) {
      class_info(state, self, true);
      return;
    }

    class_info(state, self);
    std::cout << ": " << size << std::endl;
    ++level;
    for(size_t i = 0; i < stop; i++) {
      indent(level);
      Object* obj = ary->get(state, i);
      if(obj == ary) {
        class_info(state, obj, true);
      } else {
        obj->show(state, level);
      }
    }
    if(ary->size() > stop) ellipsis(level);
    close_body(level);
  }
}
<commit_msg>And add the header.<commit_after>#include "vm.hpp"
#include "vm/object_utils.hpp"

#include "builtin/array.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/tuple.hpp"
#include "builtin/class.hpp"
#include "objectmemory.hpp"
#include "primitives.hpp"

#include <iostream>
#include <cmath>

/* Implementation certain Array methods. These methods are just
 * the ones the VM requires, not the entire set of all Array methods.
 * This includes methods required to implement certain Array
 * primitives. */

namespace rubinius {

  void Array::init(STATE) {
    GO(array).set(state->new_class("Array", G(object)));
    G(array)->set_object_type(state, ArrayType);

    native_int wordsize = as<Fixnum>(
        G(rubinius)->get_const(state, "WORDSIZE"))->to_native();
    size_t maxsize = ((size_t)::exp2(wordsize)) / (wordsize/8U);
    G(array)->set_const(state, "MAX_SIZE", Fixnum::from(maxsize));
  }

  size_t Array::size() {
    return total_->to_native();
  }

  Array* Array::create(STATE, size_t idx) {
    Array* ary;
    ary = state->new_object<Array>(G(array));

    ary->setup(state, idx);

    return ary;
  }

  // 'self' is passed in automatically by the primitive glue
  Array* Array::allocate(STATE, Object* self) {
    Array* ary = Array::create(state, 0U);
    ary->klass(state, (Class*)self);
    return ary;
  }

  Array* Array::from_tuple(STATE, Tuple* tup) {
    size_t length = tup->num_fields();
    Array* ary = Array::create(state, length);
    ary->tuple_->copy_from(state, tup,
			   Fixnum::from(0), Fixnum::from(length),
			   Fixnum::from(0));
    ary->total(state, Fixnum::from(length));
    return ary;
  }

  void Array::setup(STATE, size_t size) {
    this->tuple(state, Tuple::create(state, size));
    this->start(state, Fixnum::from(0));
    this->total(state, Fixnum::from(0));
  }

  // NOTE: We don't use Primitives::failure() here because the wrapper
  // code makes sure we're only called when the arity and type are correct.
  // Thus we know that this is a simple a[n] case only, which we can
  // fully handle.
  Object* Array::aref(STATE, Fixnum* idx) {
    native_int index = idx->to_native();
    const native_int start = start_->to_native();
    const native_int total = start + total_->to_native();

    // Handle negative indexes
    if(index < 0) {
      index += total;
    } else {
      index += start;
    }

    // Off either end, return nil
    if(index >= total || index < start) return Qnil;

    return tuple_->at(state, index);
  }

  Object* Array::aset(STATE, Fixnum* idx, Object* val) {
    native_int index = idx->to_native();

    if(index < 0) {
      return Primitives::failure();
    }

    return this->set(state, index, val);
  }

  Object* Array::get(STATE, size_t idx) {
    if(idx >= (size_t)total_->to_native()) {
      return Qnil;
    }

    idx += start_->to_native();

    return tuple_->at(state, idx);
  }

  Object* Array::set(STATE, size_t idx, Object* val) {
    size_t tuple_size = tuple_->num_fields();
    size_t oidx = idx;
    idx += start_->to_native();

    if(idx >= tuple_size) {
      // Uses the same algo as 1.8 to resize the tuple
      size_t new_size = tuple_size / 2;
      if(new_size < 3) {
        new_size = 3;
      }

      Tuple* nt = Tuple::create(state, new_size+idx);
      nt->copy_from(state, tuple_, start_, total_, Fixnum::from(0));
      tuple(state, nt);
      start(state, Fixnum::from(0));
      idx = oidx;
    }

    tuple_->put(state, idx, val);
    if((size_t)total_->to_native() <= oidx) {
      total(state, Fixnum::from(oidx+1));
    }
    return val;
  }

  void Array::unshift(STATE, Object* val) {
    size_t new_size = total_->to_native() + 1;
    size_t lend = start_->to_native();

    if(lend > 0) {
      tuple_->put(state, lend-1, val);
      start(state, Fixnum::from(lend-1));
      total(state, Fixnum::from(new_size));
    } else {
      Tuple* nt = Tuple::create(state, new_size);
      nt->copy_from(state, tuple_, start_, total_,
		    Fixnum::from(1));
      nt->put(state, 0, val);

      total(state, Fixnum::from(new_size));
      start(state, Fixnum::from(0));
      tuple(state, nt);
    }
  }

  Object* Array::shift(STATE) {
    size_t cnt = total_->to_native();

    if(cnt == 0) return Qnil;
    Object* obj = get(state, 0);
    set(state, 0, Qnil);
    start(state, Fixnum::from(start_->to_native() + 1));
    total(state, Fixnum::from(cnt - 1));
    return obj;
  }

  Object* Array::append(STATE, Object* val) {
    set(state, (size_t)total_->to_native(), val);
    return val;
  }

  bool Array::includes_p(STATE, Object* val) {
    size_t cnt = total_->to_native();

    for(size_t i = 0; i < cnt; i++) {
      if(get(state, i) == val) return true;
    }

    return false;
  }

  Object* Array::pop(STATE) {
    size_t cnt = total_->to_native();

    if(cnt == 0) return Qnil;
    Object *obj = get(state, cnt - 1);
    set(state, cnt-1, Qnil);
    total(state, Fixnum::from(cnt - 1));
    return obj;
  }

  void Array::Info::show(STATE, Object* self, int level) {
    Array* ary = as<Array>(self);
    size_t size = ary->size();
    size_t stop = size < 5 ? size : 5;

    if(size == 0) {
      class_info(state, self, true);
      return;
    }

    class_info(state, self);
    std::cout << ": " << size << std::endl;
    ++level;
    for(size_t i = 0; i < stop; i++) {
      indent(level);
      Object* obj = ary->get(state, i);
      if(obj == ary) {
        class_info(state, obj, true);
      } else {
        obj->show(state, level);
      }
    }
    if(ary->size() > stop) ellipsis(level);
    close_body(level);
  }
}
<|endoftext|>


<commit_before>#include "builtin/array.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/string.hpp"

#include "objectmemory.hpp"
#include "vm.hpp"
#include "vm/object_utils.hpp"
#include "primitives.hpp"
#include "configuration.hpp"

#include <gdtoa.h>

#include <string.h>
#include <math.h>
#include <iostream>
#include <sstream>

#include "missing/math.h"

namespace rubinius {

  void Float::init(STATE) {
    GO(floatpoint).set(state->new_class("Float", G(numeric)));
    G(floatpoint)->set_object_type(state, FloatType);

    G(floatpoint)->set_const(state, "RADIX",      Fixnum::from(FLT_RADIX));
    G(floatpoint)->set_const(state, "ROUNDS",     Fixnum::from(FLT_ROUNDS));
    G(floatpoint)->set_const(state, "MIN",        Float::create(state, DBL_MIN));
    G(floatpoint)->set_const(state, "MAX",        Float::create(state, DBL_MAX));
    G(floatpoint)->set_const(state, "MIN_EXP",    Fixnum::from(DBL_MIN_EXP));
    G(floatpoint)->set_const(state, "MAX_EXP",    Fixnum::from(DBL_MAX_EXP));
    G(floatpoint)->set_const(state, "MIN_10_EXP", Fixnum::from(DBL_MIN_10_EXP));
    G(floatpoint)->set_const(state, "MAX_10_EXP", Fixnum::from(DBL_MAX_10_EXP));
    G(floatpoint)->set_const(state, "DIG",        Fixnum::from(DBL_DIG));
    G(floatpoint)->set_const(state, "MANT_DIG",   Fixnum::from(DBL_MANT_DIG));
    G(floatpoint)->set_const(state, "EPSILON",    Float::create(state, DBL_EPSILON));

  }

  Float* Float::create(STATE, double val) {
    Float* flt = state->new_struct<Float>(G(floatpoint));
    flt->val = val;
    return flt;
  }

  Float* Float::create(STATE, float val) {
    return Float::create(state, (double)val);
  }

  Float* Float::create(STATE, native_int val) {
    return Float::create(state, (double)val);
  }

  Float* Float::coerce(STATE, Object* value) {
    if(value->fixnum_p()) {
      return Float::create(state, (double)(as<Fixnum>(value)->to_native()));
    } else if(kind_of<Bignum>(value)) {
      return Float::create(state, as<Bignum>(value)->to_double(state));
    }

    /* FIXME this used to just return value, but this wants to coerce, so
     * we give a default float value of 0.0 back instead. */
    return Float::create(state, 0.0);
  }

  Float* Float::add(STATE, Float* other) {
    return Float::create(state, this->val + other->val);
  }

  Float* Float::add(STATE, Integer* other) {
    return Float::create(state, this->val + Float::coerce(state, other)->val);
  }

  Float* Float::sub(STATE, Float* other) {
    return Float::create(state, this->val - other->val);
  }

  Float* Float::sub(STATE, Integer* other) {
    return Float::create(state, this->val - Float::coerce(state, other)->val);
  }

  Float* Float::mul(STATE, Float* other) {
    return Float::create(state, this->val * other->val);
  }

  Float* Float::mul(STATE, Integer* other) {
    return Float::create(state, this->val * Float::coerce(state, other)->val);
  }

  Float* Float::fpow(STATE, Float* other) {
    return Float::create(state, pow(this->val, other->val));
  }

  Float* Float::fpow(STATE, Integer* other) {
    return Float::create(state, pow(this->val, Float::coerce(state, other)->val));
  }

  Float* Float::div(STATE, Float* other) {
    return Float::create(state, this->val / other->val);
  }

  Float* Float::div(STATE, Integer* other) {
    return Float::create(state, this->val / Float::coerce(state, other)->val);
  }

  Float* Float::mod(STATE, Float* other) {
    double res = fmod(this->val, other->val);
    if((other->val < 0.0 && this->val > 0.0 && res != 0) ||
       (other->val > 0.0 && this->val < 0.0 && res != 0)) {
      res += other->val;
    }
    return Float::create(state, res);
  }

  Float* Float::mod(STATE, Integer* other) {
    return mod(state, Float::coerce(state, other));
  }

  Array* Float::divmod(STATE, Float* other) {
    if(LANGUAGE_19_ENABLED(state)) {
      if(other->val == 0.0) {
        Exception::zero_division_error(state, "divided by 0");
      }
    }

    Array* ary = Array::create(state, 2);
    ary->set(state, 0, Bignum::from_double(state, floor(this->val / other->val) ));
    ary->set(state, 1, mod(state, other));
    return ary;
  }

  Array* Float::divmod(STATE, Integer* other) {
    return divmod(state, Float::coerce(state, other));
  }

  Float* Float::neg(STATE) {
    return Float::create(state, -this->val);
  }

  Object* Float::equal(STATE, Float* other) {
    if(this->val == other->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::equal(STATE, Integer* other) {
    Float* o = Float::coerce(state, other);
    if(this->val == o->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::eql(STATE, Float* other) {
    if(this->val == other->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::eql(STATE, Integer* other) {
    return Qfalse;
  }

  Object* Float::compare(STATE, Float* other) {
    if(this->val == other->val) {
      return Fixnum::from(0);
    } else if(this->val > other->val) {
      return Fixnum::from(1);
    } else if(this->val < other->val){
      return Fixnum::from(-1);
    } else {
      return Qnil;
    }
  }

  Object* Float::compare(STATE, Integer* other) {
    if(isinf(this->val)) {
      if(this->val > 0) {
          return Fixnum::from(1);
      } else {
        return Fixnum::from(-1);
      }
    }
    Float* o = Float::coerce(state, other);
    if(this->val == o->val) {
      return Fixnum::from(0);
    } else if(this->val > o->val) {
      return Fixnum::from(1);
    } else if(this->val < o->val){
      return Fixnum::from(-1);
    } else {
      return Qnil;
    }
  }

  Object* Float::gt(STATE, Float* other) {
    return this->val > other->val ? Qtrue : Qfalse;
  }

  Object* Float::gt(STATE, Integer* other) {
    return this->val > Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::ge(STATE, Float* other) {
    return this->val >= other->val ? Qtrue : Qfalse;
  }

  Object* Float::ge(STATE, Integer* other) {
    return this->val >= Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::lt(STATE, Float* other) {
    return this->val < other->val ? Qtrue : Qfalse;
  }

  Object* Float::lt(STATE, Integer* other) {
    return this->val < Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::le(STATE, Float* other) {
    return this->val <= other->val ? Qtrue : Qfalse;
  }

  Object* Float::le(STATE, Integer* other) {
    return this->val <= Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::fisinf(STATE) {
    if(isinf(this->val) != 0) {
      return this->val < 0 ? Fixnum::from(-1) : Fixnum::from(1);
    } else {
      return Qnil;
    }
  }

  Object* Float::fisnan(STATE) {
    return isnan(this->val) == 1 ? Qtrue : Qfalse;
  }

  Integer* Float::fround(STATE) {
    double value = this->val;
    if(value > 0.0) {
      value = floor(value);
      if(this->val - value >= 0.5) value += 1.0;
    }

    if(value < 0.0) {
      value = ceil(value);
      if(value - this->val >= 0.5) value -= 1.0;
    }
    return Bignum::from_double(state, value);
  }

  Integer* Float::to_i(STATE) {
    if(this->val > 0.0) {
      return Bignum::from_double(state, floor(this->val));
    } else if(this->val < 0.0) {
      return Bignum::from_double(state, ceil(this->val));
    }
    return Bignum::from_double(state, this->val);
  }

/* It requires "%.1022f" to print all digits of Float::MIN.
 * If you really need more digits than that, change this constant.
 */
#define FLOAT_TO_S_STRLEN   1280

  String* Float::to_s_formatted(STATE, String* format) {
    char str[FLOAT_TO_S_STRLEN];

    size_t size = snprintf(str, FLOAT_TO_S_STRLEN, format->c_str(state), val);

    if(size >= FLOAT_TO_S_STRLEN) {
      std::ostringstream msg;
      msg << "formatted string exceeds " << FLOAT_TO_S_STRLEN << " bytes";
      Exception::argument_error(state, msg.str().c_str());
    }

    return String::create(state, str, size);
  }

  String* Float::to_s_minimal(STATE) {
    char str[FLOAT_TO_S_STRLEN];

    if(g_dfmt(str, &val, 0, FLOAT_TO_S_STRLEN) == 0) {
      return reinterpret_cast<String*>(kPrimitiveFailed);
    }

    String* s = String::create(state, str);
    if(is_tainted_p()) s->set_tainted();

    return s;
  }

  String* Float::to_packed(STATE, Object* want_double) {
    char str[sizeof(double)];
    int sz;

    if (want_double == Qtrue) {
      double* p = (double *)str;
      *p = this->val;
      sz = 8;
    }
    else {
      float* p = (float *)str;
      *p = this->val;
      sz = 4;
    }

    return String::create(state, str, sz);
  }

  void Float::into_string(STATE, char* buf, size_t sz) {
    snprintf(buf, sz, "%+.17e", val);
  }

  void Float::Info::mark(Object* t, ObjectMark& mark) { }

  void Float::Info::show(STATE, Object* self, int level) {
    Float* f = as<Float>(self);
    std::cout << f->val << std::endl;
  }

  void Float::Info::show_simple(STATE, Object* self, int level) {
    show(state, self, level);
  }
}
<commit_msg>Float#% Float#modulo raise ZeroDivisionError when other is zero in 1.9<commit_after>#include "builtin/array.hpp"
#include "builtin/exception.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/string.hpp"

#include "objectmemory.hpp"
#include "vm.hpp"
#include "vm/object_utils.hpp"
#include "primitives.hpp"
#include "configuration.hpp"

#include <gdtoa.h>

#include <string.h>
#include <math.h>
#include <iostream>
#include <sstream>

#include "missing/math.h"

namespace rubinius {

  void Float::init(STATE) {
    GO(floatpoint).set(state->new_class("Float", G(numeric)));
    G(floatpoint)->set_object_type(state, FloatType);

    G(floatpoint)->set_const(state, "RADIX",      Fixnum::from(FLT_RADIX));
    G(floatpoint)->set_const(state, "ROUNDS",     Fixnum::from(FLT_ROUNDS));
    G(floatpoint)->set_const(state, "MIN",        Float::create(state, DBL_MIN));
    G(floatpoint)->set_const(state, "MAX",        Float::create(state, DBL_MAX));
    G(floatpoint)->set_const(state, "MIN_EXP",    Fixnum::from(DBL_MIN_EXP));
    G(floatpoint)->set_const(state, "MAX_EXP",    Fixnum::from(DBL_MAX_EXP));
    G(floatpoint)->set_const(state, "MIN_10_EXP", Fixnum::from(DBL_MIN_10_EXP));
    G(floatpoint)->set_const(state, "MAX_10_EXP", Fixnum::from(DBL_MAX_10_EXP));
    G(floatpoint)->set_const(state, "DIG",        Fixnum::from(DBL_DIG));
    G(floatpoint)->set_const(state, "MANT_DIG",   Fixnum::from(DBL_MANT_DIG));
    G(floatpoint)->set_const(state, "EPSILON",    Float::create(state, DBL_EPSILON));

  }

  Float* Float::create(STATE, double val) {
    Float* flt = state->new_struct<Float>(G(floatpoint));
    flt->val = val;
    return flt;
  }

  Float* Float::create(STATE, float val) {
    return Float::create(state, (double)val);
  }

  Float* Float::create(STATE, native_int val) {
    return Float::create(state, (double)val);
  }

  Float* Float::coerce(STATE, Object* value) {
    if(value->fixnum_p()) {
      return Float::create(state, (double)(as<Fixnum>(value)->to_native()));
    } else if(kind_of<Bignum>(value)) {
      return Float::create(state, as<Bignum>(value)->to_double(state));
    }

    /* FIXME this used to just return value, but this wants to coerce, so
     * we give a default float value of 0.0 back instead. */
    return Float::create(state, 0.0);
  }

  Float* Float::add(STATE, Float* other) {
    return Float::create(state, this->val + other->val);
  }

  Float* Float::add(STATE, Integer* other) {
    return Float::create(state, this->val + Float::coerce(state, other)->val);
  }

  Float* Float::sub(STATE, Float* other) {
    return Float::create(state, this->val - other->val);
  }

  Float* Float::sub(STATE, Integer* other) {
    return Float::create(state, this->val - Float::coerce(state, other)->val);
  }

  Float* Float::mul(STATE, Float* other) {
    return Float::create(state, this->val * other->val);
  }

  Float* Float::mul(STATE, Integer* other) {
    return Float::create(state, this->val * Float::coerce(state, other)->val);
  }

  Float* Float::fpow(STATE, Float* other) {
    return Float::create(state, pow(this->val, other->val));
  }

  Float* Float::fpow(STATE, Integer* other) {
    return Float::create(state, pow(this->val, Float::coerce(state, other)->val));
  }

  Float* Float::div(STATE, Float* other) {
    return Float::create(state, this->val / other->val);
  }

  Float* Float::div(STATE, Integer* other) {
    return Float::create(state, this->val / Float::coerce(state, other)->val);
  }

  Float* Float::mod(STATE, Float* other) {
    if(LANGUAGE_19_ENABLED(state)) {
      if(other->val == 0.0) {
        Exception::zero_division_error(state, "divided by 0");
      }
    }

    double res = fmod(this->val, other->val);
    if((other->val < 0.0 && this->val > 0.0 && res != 0) ||
       (other->val > 0.0 && this->val < 0.0 && res != 0)) {
      res += other->val;
    }
    return Float::create(state, res);
  }

  Float* Float::mod(STATE, Integer* other) {
    return mod(state, Float::coerce(state, other));
  }

  Array* Float::divmod(STATE, Float* other) {
    if(LANGUAGE_19_ENABLED(state)) {
      if(other->val == 0.0) {
        Exception::zero_division_error(state, "divided by 0");
      }
    }

    Array* ary = Array::create(state, 2);
    ary->set(state, 0, Bignum::from_double(state, floor(this->val / other->val) ));
    ary->set(state, 1, mod(state, other));
    return ary;
  }

  Array* Float::divmod(STATE, Integer* other) {
    return divmod(state, Float::coerce(state, other));
  }

  Float* Float::neg(STATE) {
    return Float::create(state, -this->val);
  }

  Object* Float::equal(STATE, Float* other) {
    if(this->val == other->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::equal(STATE, Integer* other) {
    Float* o = Float::coerce(state, other);
    if(this->val == o->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::eql(STATE, Float* other) {
    if(this->val == other->val) {
      return Qtrue;
    }
    return Qfalse;
  }

  Object* Float::eql(STATE, Integer* other) {
    return Qfalse;
  }

  Object* Float::compare(STATE, Float* other) {
    if(this->val == other->val) {
      return Fixnum::from(0);
    } else if(this->val > other->val) {
      return Fixnum::from(1);
    } else if(this->val < other->val){
      return Fixnum::from(-1);
    } else {
      return Qnil;
    }
  }

  Object* Float::compare(STATE, Integer* other) {
    if(isinf(this->val)) {
      if(this->val > 0) {
          return Fixnum::from(1);
      } else {
        return Fixnum::from(-1);
      }
    }
    Float* o = Float::coerce(state, other);
    if(this->val == o->val) {
      return Fixnum::from(0);
    } else if(this->val > o->val) {
      return Fixnum::from(1);
    } else if(this->val < o->val){
      return Fixnum::from(-1);
    } else {
      return Qnil;
    }
  }

  Object* Float::gt(STATE, Float* other) {
    return this->val > other->val ? Qtrue : Qfalse;
  }

  Object* Float::gt(STATE, Integer* other) {
    return this->val > Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::ge(STATE, Float* other) {
    return this->val >= other->val ? Qtrue : Qfalse;
  }

  Object* Float::ge(STATE, Integer* other) {
    return this->val >= Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::lt(STATE, Float* other) {
    return this->val < other->val ? Qtrue : Qfalse;
  }

  Object* Float::lt(STATE, Integer* other) {
    return this->val < Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::le(STATE, Float* other) {
    return this->val <= other->val ? Qtrue : Qfalse;
  }

  Object* Float::le(STATE, Integer* other) {
    return this->val <= Float::coerce(state, other)->val ? Qtrue : Qfalse;
  }

  Object* Float::fisinf(STATE) {
    if(isinf(this->val) != 0) {
      return this->val < 0 ? Fixnum::from(-1) : Fixnum::from(1);
    } else {
      return Qnil;
    }
  }

  Object* Float::fisnan(STATE) {
    return isnan(this->val) == 1 ? Qtrue : Qfalse;
  }

  Integer* Float::fround(STATE) {
    double value = this->val;
    if(value > 0.0) {
      value = floor(value);
      if(this->val - value >= 0.5) value += 1.0;
    }

    if(value < 0.0) {
      value = ceil(value);
      if(value - this->val >= 0.5) value -= 1.0;
    }
    return Bignum::from_double(state, value);
  }

  Integer* Float::to_i(STATE) {
    if(this->val > 0.0) {
      return Bignum::from_double(state, floor(this->val));
    } else if(this->val < 0.0) {
      return Bignum::from_double(state, ceil(this->val));
    }
    return Bignum::from_double(state, this->val);
  }

/* It requires "%.1022f" to print all digits of Float::MIN.
 * If you really need more digits than that, change this constant.
 */
#define FLOAT_TO_S_STRLEN   1280

  String* Float::to_s_formatted(STATE, String* format) {
    char str[FLOAT_TO_S_STRLEN];

    size_t size = snprintf(str, FLOAT_TO_S_STRLEN, format->c_str(state), val);

    if(size >= FLOAT_TO_S_STRLEN) {
      std::ostringstream msg;
      msg << "formatted string exceeds " << FLOAT_TO_S_STRLEN << " bytes";
      Exception::argument_error(state, msg.str().c_str());
    }

    return String::create(state, str, size);
  }

  String* Float::to_s_minimal(STATE) {
    char str[FLOAT_TO_S_STRLEN];

    if(g_dfmt(str, &val, 0, FLOAT_TO_S_STRLEN) == 0) {
      return reinterpret_cast<String*>(kPrimitiveFailed);
    }

    String* s = String::create(state, str);
    if(is_tainted_p()) s->set_tainted();

    return s;
  }

  String* Float::to_packed(STATE, Object* want_double) {
    char str[sizeof(double)];
    int sz;

    if (want_double == Qtrue) {
      double* p = (double *)str;
      *p = this->val;
      sz = 8;
    }
    else {
      float* p = (float *)str;
      *p = this->val;
      sz = 4;
    }

    return String::create(state, str, sz);
  }

  void Float::into_string(STATE, char* buf, size_t sz) {
    snprintf(buf, sz, "%+.17e", val);
  }

  void Float::Info::mark(Object* t, ObjectMark& mark) { }

  void Float::Info::show(STATE, Object* self, int level) {
    Float* f = as<Float>(self);
    std::cout << f->val << std::endl;
  }

  void Float::Info::show_simple(STATE, Object* self, int level) {
    show(state, self, level);
  }
}
<|endoftext|>


<commit_before>#ifndef VPP_IMAGENd_HPP__
# define VPP_IMAGENd_HPP__

# include <iostream>
# include <iod/sio.hh>
# include <vpp/core/imageNd.hh>
# include <vpp/core/boxNd.hh>
# include <vpp/core/symbols.hh>

# ifndef VPP_DEFAULT_IMAGE_ALIGNMENT

# ifdef __AVX2__
#  define VPP_DEFAULT_IMAGE_ALIGNMENT 32
# else
#  define VPP_DEFAULT_IMAGE_ALIGNMENT 16
# endif

# endif

namespace vpp
{

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd()
  {
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const std::initializer_list<int>& dims, const O&... options)
  {
    allocate(dims, iod::D(options...));
    index_rows();
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const std::vector<int>& dims, const O&... options)
  {
    allocate(dims, iod::D(options...));
    index_rows();
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int ncols, const O&... options)
    : imageNd(make_box1d(ncols), options...)
  {
    static_assert(N == 1, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int nrows, int ncols, const O&... options)
    : imageNd(make_box2d(nrows, ncols), options...)
  {
    static_assert(N == 2, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int nslices, int nrows, int ncols, const O&... options)
    : imageNd(make_box3d(nslices, nrows, ncols), options...)
  {
    static_assert(N == 3, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd(imageNd<V, N>&& other)
    : ptr_(std::move(other.ptr_))
  {
  }

  template <typename V, unsigned N>
  imageNd<V, N>& imageNd<V, N>::operator=(const imageNd<V, N>& other)
  {
    ptr_ = other.ptr_;
    return *this;
  }

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd(const imageNd<V, N>& other)
  {
    *this = other;
  }

  template <typename V, unsigned N>
  imageNd<V, N>& imageNd<V, N>::operator=(imageNd<V, N>&& other)
  {
    ptr_ = std::move(other.ptr_);
    return *this;
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const boxNd<N>& domain, const O&... _options)
  {
    std::vector<int> dims(N);

    for (int i = 0; i < int(N); i++)
      dims[i] = domain.size(i);

    const auto options = iod::D(_options...);

    static_assert(
      !options.has(_data) or options.has(_pitch),
      "You must provide the pitch (Number of bits between the begining of to successive lines when providing a data pointer the image constructor.");

    if (options.has(_data))
    {
      ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());

      ptr_->data_ = (V*) options.get(_data, (V*)0);
      ptr_->begin_ = ptr_->data_;
      ptr_->pitch_ = options.get(_pitch, 0);
      ptr_->domain_ = domain;
      ptr_->buffer_domain_ = domain;
      ptr_->border_ = options.get(_border, 0);

      // compute alignement.
      unsigned int data_al = 1;
      typedef unsigned long UL;
      while ((UL(ptr_->data_) % (data_al * 2)) == 0) data_al *= 2;
      unsigned int pitch_al = 1;
      while ((UL(ptr_->pitch_) % (pitch_al * 2)) == 0) pitch_al *= 2;
      ptr_->alignment_ = std::min(data_al, pitch_al);

      int size = ptr_->pitch_;
      for (int n = 0; n < N - 1; n++)
        size *= ptr_->domain_.size(n);

      ptr_->data_end_ = (V*)((char*) ptr_->data_ + size);
    }
    else
      allocate(dims, options);

    index_rows();
  }

  template <typename V, unsigned N>
  imageNd<V, N>::~imageNd()
  {
    // The shared_ptr this_->ptr_ will destroy the data if needed.
  }

  template <typename V, unsigned N>
  template <typename... O>
  void imageNd<V, N>::allocate(const std::vector<int>& dims, const iod::sio<O...>& options)
  {
    const int align_size = options.get(_aligned, VPP_DEFAULT_IMAGE_ALIGNMENT); // Memory alignment of rows.
    assert(align_size != 0);
    typedef unsigned long long ULL;
    ptr_ = std::make_shared<imageNd_data<V, N>>();
    auto& d = *ptr_;
    d.border_ = options.get(_border, 0);
    d.alignment_ = align_size;

    int border_size = d.border_ * sizeof(V);
    int border_padding = 0;
    if (border_size % align_size)
    {
      border_padding = align_size - (border_size % align_size);
      border_size += border_padding;
    }

    d.pitch_ = dims[N - 1] * sizeof(V) + border_size * 2;
    if (d.pitch_ % align_size) d.pitch_ += align_size - (d.pitch_ % align_size);

    int size = 1;
    for (int i = 0; i < N - 1; i++)
      size *= dims[i] + (d.border_ * 2);
    size *= d.pitch_;

    d.data_ = (V*) malloc(align_size + size);
    d.data_sptr_ = std::shared_ptr<void>(d.data_, [] (V* p) {
        free((char*)p);
      });

    if (ULL(d.data_) % align_size)
      d.data_ = (V*)((char*)(d.data_) + align_size - int(ULL(d.data_) % align_size));

    d.data_end_ = d.data_ + size / sizeof(V);
    assert(!(ULL(d.data_) % align_size));
    d.domain_.p1() = vint<N>::Zero();
    for (unsigned i = 0; i < N; i++)
      d.domain_.p2()[i] = dims[i] - 1;

    // Set begin_, the address of the first pixel.
    vint<N> p = vint<N>::Ones() * d.border_;
    d.begin_ = (V*)((char*)d.data_ + border_padding + coords_to_offset(p));
    d.buffer_domain_ = d.domain_;
  }

  template <typename V, unsigned N>
  void imageNd<V, N>::index_rows()
  {

    std::vector<V*>& rows = ptr_->rows_;
    rows.clear();
    boxNd<N - 1> row_domain(domain_with_border().p1().template segment<N - 1>(0),
                            domain_with_border().p2().template segment<N - 1>(0));

    int ras = 0;
    for(vint<N - 1> r : row_domain)
    {
      vint<N> p = domain().p1();
      p.template segment<N - 1>(0) = r;

      rows.push_back(this->address_of(p));

      if (p == vint<N>::Zero())
        ras = rows.size() - 1;
    }

    ptr_->rows_array_start_ = &rows[ras];
  }

  template <typename V, unsigned N>
  int imageNd<V, N>::coords_to_offset(const vint<N>& p) const
  {
    int row_idx = p[N-2];
    int ds = 1;
    for (int i = N - 3; i >= 0; i--)
    {
      ds *= ptr_->buffer_domain_.size(i + 1);
      row_idx += ds * p[i];
    }
    return row_idx * ptr_->pitch_ + p[N - 1] * sizeof(V);
  }

  template <typename V, unsigned N>
  V&
  imageNd<V, N>::operator()(const vint<N>& p)
  {
    assert(domain_with_border().has(p));
    V* addr = (V*)((char*)ptr_->begin_ + coords_to_offset(p));
    assert(addr < ptr_->data_end_);
    return *addr;
  }

  template <typename V, unsigned N>
  const V&
  imageNd<V, N>::operator()(const vint<N>& p) const
  {
    assert(domain_with_border().has(p));
    const V* addr = (V*)((char*)ptr_->begin_ + coords_to_offset(p));
    assert(addr < ptr_->data_end_);
    return *addr;
  }

  template <typename V, unsigned N>
  V*
  imageNd<V, N>::operator[](int r)
  {
    return ptr_->rows_array_start_[r];
  }

  template <typename V, unsigned N>
  const V*
  imageNd<V, N>::operator[](int r) const
  {
    return ptr_->rows_array_start_[r];
  }

  template <typename V, unsigned N>
  V
  imageNd<V, N>::linear_interpolate(const vfloat<N>& p) const
  {
    static_assert(N == 2, "linear_interpolate only supports 2d images.");

    vint2 x = p.template cast<int>();
    float a0 = p[0] - x[0];
    float a1 = p[1] - x[1];

    const V* l1 = address_of(x);
    const V* l2 = (const V*)((const char*)l1 + ptr_->pitch_);

    //typedef plus_promotion<V> S;
    typedef cast_to_float<V> S;

    return vpp::cast<V>((1 - a0) * (1 - a1) *  vpp::cast<S>(l1[0]) +
                        a0 * (1 - a1) *  vpp::cast<S>(l2[0]) +
                        (1 - a0) * a1 *  vpp::cast<S>(l1[1]) +
                        a0 * a1 *  vpp::cast<S>(l2[1]));
  }

  template <typename V, unsigned N>
  V*
  imageNd<V, N>::address_of(const vint<N>& p)
  {
    return (V*)((char*)(ptr_->begin_) + coords_to_offset(p));
  }

  template <typename V, unsigned N>
  const V*
  imageNd<V, N>::address_of(const vint<N>& p) const
  {
    return (V*)((char*)(ptr_->begin_) + coords_to_offset(p));
  }

  template <typename V, unsigned N>
  int
  imageNd<V, N>::offset_of(const vint<N>& p) const
  {
    return coords_to_offset(p);
  }

  template <typename V, unsigned N>
  imageNd<V, N>
  imageNd<V, N>::subimage(const boxNd<N>& d)
  {
    imageNd<V, N> res;
    res.ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());
    *res.ptr_.get() = *this->ptr_.get(); // Copy the image data.
    res.ptr_->begin_ = address_of(d.p1());
    boxNd<N> domain = d;
    domain.p2() -= domain.p1();
    domain.p1() -= domain.p1();
    res.ptr_->domain_ = domain;

    for (V*& r_start : res.ptr_->rows_)
      r_start += d.p1()[1] - this->domain().p1()[1];

    res.ptr_->rows_array_start_ += d.p1()[0] - this->domain().p1()[0];

    return res;
  }

  template <typename V, unsigned N>
  const imageNd<V, N>
  imageNd<V, N>::const_subimage(const boxNd<N>& d) const
  {
    imageNd<V, N> res;

    res.ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());
    *res.ptr_.get() = *this->ptr_.get();
    res.ptr_->begin_ = const_cast<V*>(address_of(d.p1()));
    boxNd<N> domain = d;
    domain.p2() -= domain.p1();
    domain.p1() -= domain.p1();
    res.ptr_->domain_ = domain;

    for (V*& r_start : res.ptr_->rows_)
      r_start += d.p1()[1] - this->domain().p1()[1];

    res.ptr_->rows_array_start_ += d.p1()[0] - this->domain().p1()[0];

    return res;
  }

};

#endif
<commit_msg>img(p) is not equivalent to the faster img[][]. Fix a bug in subimage.<commit_after>#ifndef VPP_IMAGENd_HPP__
# define VPP_IMAGENd_HPP__

# include <iostream>
# include <iod/sio.hh>
# include <vpp/core/imageNd.hh>
# include <vpp/core/boxNd.hh>
# include <vpp/core/symbols.hh>

# ifndef VPP_DEFAULT_IMAGE_ALIGNMENT

# ifdef __AVX2__
#  define VPP_DEFAULT_IMAGE_ALIGNMENT 32
# else
#  define VPP_DEFAULT_IMAGE_ALIGNMENT 16
# endif

# endif

namespace vpp
{

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd()
  {
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const std::initializer_list<int>& dims, const O&... options)
  {
    allocate(dims, iod::D(options...));
    index_rows();
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const std::vector<int>& dims, const O&... options)
  {
    allocate(dims, iod::D(options...));
    index_rows();
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int ncols, const O&... options)
    : imageNd(make_box1d(ncols), options...)
  {
    static_assert(N == 1, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int nrows, int ncols, const O&... options)
    : imageNd(make_box2d(nrows, ncols), options...)
  {
    static_assert(N == 2, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(int nslices, int nrows, int ncols, const O&... options)
    : imageNd(make_box3d(nslices, nrows, ncols), options...)
  {
    static_assert(N == 3, "ImageNd constructor: bad dimension.");
  }

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd(imageNd<V, N>&& other)
    : ptr_(std::move(other.ptr_))
  {
  }

  template <typename V, unsigned N>
  imageNd<V, N>& imageNd<V, N>::operator=(const imageNd<V, N>& other)
  {
    ptr_ = other.ptr_;
    return *this;
  }

  template <typename V, unsigned N>
  imageNd<V, N>::imageNd(const imageNd<V, N>& other)
  {
    *this = other;
  }

  template <typename V, unsigned N>
  imageNd<V, N>& imageNd<V, N>::operator=(imageNd<V, N>&& other)
  {
    ptr_ = std::move(other.ptr_);
    return *this;
  }

  template <typename V, unsigned N>
  template <typename... O>
  imageNd<V, N>::imageNd(const boxNd<N>& domain, const O&... _options)
  {
    std::vector<int> dims(N);

    for (int i = 0; i < int(N); i++)
      dims[i] = domain.size(i);

    const auto options = iod::D(_options...);

    static_assert(
      !options.has(_data) or options.has(_pitch),
      "You must provide the pitch (Number of bits between the begining of to successive lines when providing a data pointer the image constructor.");

    if (options.has(_data))
    {
      ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());

      ptr_->data_ = (V*) options.get(_data, (V*)0);
      ptr_->begin_ = ptr_->data_;
      ptr_->pitch_ = options.get(_pitch, 0);
      ptr_->domain_ = domain;
      ptr_->buffer_domain_ = domain;
      ptr_->border_ = options.get(_border, 0);

      // compute alignement.
      unsigned int data_al = 1;
      typedef unsigned long UL;
      while ((UL(ptr_->data_) % (data_al * 2)) == 0) data_al *= 2;
      unsigned int pitch_al = 1;
      while ((UL(ptr_->pitch_) % (pitch_al * 2)) == 0) pitch_al *= 2;
      ptr_->alignment_ = std::min(data_al, pitch_al);

      int size = ptr_->pitch_;
      for (int n = 0; n < N - 1; n++)
        size *= ptr_->domain_.size(n);

      ptr_->data_end_ = (V*)((char*) ptr_->data_ + size);
    }
    else
      allocate(dims, options);

    index_rows();
  }

  template <typename V, unsigned N>
  imageNd<V, N>::~imageNd()
  {
    // The shared_ptr this_->ptr_ will destroy the data if needed.
  }

  template <typename V, unsigned N>
  template <typename... O>
  void imageNd<V, N>::allocate(const std::vector<int>& dims, const iod::sio<O...>& options)
  {
    const int align_size = options.get(_aligned, VPP_DEFAULT_IMAGE_ALIGNMENT); // Memory alignment of rows.
    assert(align_size != 0);
    typedef unsigned long long ULL;
    ptr_ = std::make_shared<imageNd_data<V, N>>();
    auto& d = *ptr_;
    d.border_ = options.get(_border, 0);
    d.alignment_ = align_size;

    int border_size = d.border_ * sizeof(V);
    int border_padding = 0;
    if (border_size % align_size)
    {
      border_padding = align_size - (border_size % align_size);
      border_size += border_padding;
    }

    d.pitch_ = dims[N - 1] * sizeof(V) + border_size * 2;
    if (d.pitch_ % align_size) d.pitch_ += align_size - (d.pitch_ % align_size);

    int size = 1;
    for (int i = 0; i < N - 1; i++)
      size *= dims[i] + (d.border_ * 2);
    size *= d.pitch_;

    d.data_ = (V*) malloc(align_size + size);
    d.data_sptr_ = std::shared_ptr<void>(d.data_, [] (V* p) {
        free((char*)p);
      });

    if (ULL(d.data_) % align_size)
      d.data_ = (V*)((char*)(d.data_) + align_size - int(ULL(d.data_) % align_size));

    d.data_end_ = d.data_ + size / sizeof(V);
    assert(!(ULL(d.data_) % align_size));
    d.domain_.p1() = vint<N>::Zero();
    for (unsigned i = 0; i < N; i++)
      d.domain_.p2()[i] = dims[i] - 1;

    // Set begin_, the address of the first pixel.
    vint<N> p = vint<N>::Ones() * d.border_;
    d.begin_ = (V*)((char*)d.data_ + border_padding + coords_to_offset(p));
    d.buffer_domain_ = d.domain_;
  }

  template <typename V, unsigned N>
  void imageNd<V, N>::index_rows()
  {

    std::vector<V*>& rows = ptr_->rows_;
    rows.clear();
    boxNd<N - 1> row_domain(domain_with_border().p1().template segment<N - 1>(0),
                            domain_with_border().p2().template segment<N - 1>(0));

    int ras = 0;
    for(vint<N - 1> r : row_domain)
    {
      vint<N> p = domain().p1();
      p.template segment<N - 1>(0) = r;

      rows.push_back(this->address_of(p));

      if (p == vint<N>::Zero())
        ras = rows.size() - 1;
    }

    ptr_->rows_array_start_ = &rows[ras];
  }

  template <typename V, unsigned N>
  int imageNd<V, N>::coords_to_offset(const vint<N>& p) const
  {
    int row_idx = p[N-2];
    int ds = 1;
    for (int i = N - 3; i >= 0; i--)
    {
      ds *= ptr_->buffer_domain_.size(i + 1);
      row_idx += ds * p[i];
    }
    return row_idx * ptr_->pitch_ + p[N - 1] * sizeof(V);
  }

  template <typename V, unsigned N>
  V&
  imageNd<V, N>::operator()(const vint<N>& p)
  {
    assert(domain_with_border().has(p));
    if (N == 2)
      return (*this)[p[0]][p[1]];
    else
    {
      V* addr = (V*)((char*)ptr_->begin_ + coords_to_offset(p));
      assert(addr < ptr_->data_end_);
      return *addr;
    }
  }

  template <typename V, unsigned N>
  const V&
  imageNd<V, N>::operator()(const vint<N>& p) const
  {
    assert(domain_with_border().has(p));
    if (N == 2)
      return (*this)[p[0]][p[1]];
    else
    {
      const V* addr = (V*)((char*)ptr_->begin_ + coords_to_offset(p));
      assert(addr < ptr_->data_end_);
      return *addr;
    }
  }

  template <typename V, unsigned N>
  V*
  imageNd<V, N>::operator[](int r)
  {
    return ptr_->rows_array_start_[r];
  }

  template <typename V, unsigned N>
  const V*
  imageNd<V, N>::operator[](int r) const
  {
    return ptr_->rows_array_start_[r];
  }

  template <typename V, unsigned N>
  V
  imageNd<V, N>::linear_interpolate(const vfloat<N>& p) const
  {
    static_assert(N == 2, "linear_interpolate only supports 2d images.");

    vint2 x = p.template cast<int>();
    float a0 = p[0] - x[0];
    float a1 = p[1] - x[1];

    const V* l1 = address_of(x);
    const V* l2 = (const V*)((const char*)l1 + ptr_->pitch_);

    //typedef plus_promotion<V> S;
    typedef cast_to_float<V> S;

    return vpp::cast<V>((1 - a0) * (1 - a1) *  vpp::cast<S>(l1[0]) +
                        a0 * (1 - a1) *  vpp::cast<S>(l2[0]) +
                        (1 - a0) * a1 *  vpp::cast<S>(l1[1]) +
                        a0 * a1 *  vpp::cast<S>(l2[1]));
  }

  template <typename V, unsigned N>
  V*
  imageNd<V, N>::address_of(const vint<N>& p)
  {
    return (V*)((char*)(ptr_->begin_) + coords_to_offset(p));
  }

  template <typename V, unsigned N>
  const V*
  imageNd<V, N>::address_of(const vint<N>& p) const
  {
    return (V*)((char*)(ptr_->begin_) + coords_to_offset(p));
  }

  template <typename V, unsigned N>
  int
  imageNd<V, N>::offset_of(const vint<N>& p) const
  {
    return coords_to_offset(p);
  }

  template <typename V, unsigned N>
  imageNd<V, N>
  imageNd<V, N>::subimage(const boxNd<N>& d)
  {
    imageNd<V, N> res;
    res.ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());
    *res.ptr_.get() = *this->ptr_.get(); // Copy the image data.
    res.ptr_->begin_ = address_of(d.p1());
    boxNd<N> domain = d;
    domain.p2() -= domain.p1();
    domain.p1() -= domain.p1();
    res.ptr_->domain_ = domain;

    for (auto& r_start : res.ptr_->rows_)
      r_start += d.p1()[1] - this->domain().p1()[1];

    res.ptr_->rows_array_start_ = &res.ptr_->rows_.front() +
      (*this->ptr_->rows_array_start_ - &(*this->ptr_->rows_.front()))
      + (d.p1()[0] - this->domain().p1()[0]);

    return res;
  }

  template <typename V, unsigned N>
  const imageNd<V, N>
  imageNd<V, N>::const_subimage(const boxNd<N>& d) const
  {
    imageNd<V, N> res;

    res.ptr_ = std::shared_ptr<imageNd_data<V, N>>(new imageNd_data<V, N>());
    *res.ptr_.get() = *this->ptr_.get();
    res.ptr_->begin_ = const_cast<V*>(address_of(d.p1()));
    boxNd<N> domain = d;
    domain.p2() -= domain.p1();
    domain.p1() -= domain.p1();
    res.ptr_->domain_ = domain;

    for (V*& r_start : res.ptr_->rows_)
      r_start += d.p1()[1] - this->domain().p1()[1];

    res.ptr_->rows_array_start_ += d.p1()[0] - this->domain().p1()[0];

    return res;
  }

};

#endif
<|endoftext|>


<commit_before>#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

int Ws(const cv::Point2d &a, const cv::Point2d &b, const int radius) {
  return ((cv::norm(cv::Mat(a), cv::Mat(b), cv::NORM_L2) < radius) ? 1 : 0);
}

double Wm(const cv::Point2d &a, const cv::Point2d &b, const cv::Mat &grad,
          const double eta = 1.0) {
  double ga = grad.at<double>(a.y, a.x);
  double gb = grad.at<double>(b.y, b.x);
  return (0.5 * (1.0 + std::tanh(eta * (gb - ga))));
}

double Wd(const cv::Point2d &a, const cv::Point2d &b, const cv::Mat &tcurr) {
  double ta = tcurr.at<double>(a.y, a.x);
  double tb = tcurr.at<double>(b.y, b.x);
  double mult = ta * tb;
  return ((mult > 0) ? std::abs(mult) : -1.0 * std::abs(mult));
}

void ETFIteration(cv::Mat &tcurr, const cv::Mat &grad, const int kradius) {
  cv::Mat tnew = cv::Mat::zeros(tcurr.size(), CV_64FC1);
  for (uint y = 0; y < tcurr.size().height; ++y) {
    for (uint x = 0; x < tcurr.size().width; ++x) {
      const auto pa = cv::Point2d(x, y);
      double sigma = 0;
      double k = 0;
      for (uint oy = -kradius; oy <= kradius; ++oy) {
        int py = y + oy;
        if (py < 0 || py > tcurr.size().height)
          continue;
        for (uint ox = -kradius; ox <= kradius; ++ox) {
          int px = x + ox;
          if (px < 0 || px > tcurr.size().width)
            continue;
          k += 1.0;
          const auto pb = cv::Point2d(px, py);
          sigma += tcurr.at<double>(pb) * Ws(pa, pb, kradius) *
                   Wm(pa, pb, grad) * Wd(pa, pb, tcurr);
        }
      }
      tnew.at<double>(pa) = (k > 0.1) ? sigma / k : 0.0;
    }
  }
  tcurr = tnew;
}

cv::Mat coherentLines(const cv::Mat &img, const int kernel_radius = 5,
                      const int etf_iterations = 3) {
  cv::Mat gray;
  cv::cvtColor(img, gray, CV_BGR2GRAY);

  cv::Mat gx, gy, gm, gt, gmnorm;
  cv::Sobel(gray, gx, CV_16S, 1, 0, 3);
  cv::Sobel(gray, gy, CV_16S, 0, 1, 3);
  cv::magnitude(gx, gy, gm);
  cv::normalize(gm, gt, 1.0, 0.0, cv::NORM_INF);
  gt.convertTo(gmnorm, CV_64FC1);

  cv::Mat etf;
  gmnorm.copyTo(etf);
}

int main(int argc, char **argv) {
  if (argc != 2) {
    std::cout << argv[0] << " <path_to_image>" << std::endl;
    return 1;
  }

  auto img = cv::imread(argv[1]);
  cv::imshow("input", img);
  cv::waitKey(0);

  return 0;
}
<commit_msg>drawing poor results<commit_after>#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#include <iostream>

int Ws(const cv::Point2d &a, const cv::Point2d &b, const int radius) {
  return ((cv::norm(cv::Mat(a), cv::Mat(b), cv::NORM_L2) < radius) ? 1 : 0);
}

double Wm(const cv::Point2d &a, const cv::Point2d &b, const cv::Mat &grad,
          const double eta = 1.0) {
  double ga = grad.at<double>(a.y, a.x);
  double gb = grad.at<double>(b.y, b.x);
  return (0.5 * (1.0 + std::tanh(eta * (gb - ga))));
}

double Wd(const cv::Point2d &a, const cv::Point2d &b, const cv::Mat &tcurr) {
  double ta = tcurr.at<double>(a.y, a.x);
  double tb = tcurr.at<double>(b.y, b.x);
  double mult = ta * tb;
  return ((mult > 0) ? std::abs(mult) : -1.0 * std::abs(mult));
}

void ETFIteration(cv::Mat &tcurr, const cv::Mat &grad, const int kradius) {
  cv::Mat tnew = cv::Mat::zeros(tcurr.size(), CV_64FC1);
  for (auto y = 0; y < (int)tcurr.size().height; ++y) {
    for (auto x = 0; x < (int)tcurr.size().width; ++x) {
      const auto pa = cv::Point2d(x, y);
      double sigma = 0;
      double k = 0;
      for (auto oy = -kradius; oy <= kradius; ++oy) {
        int py = y + oy;
        if (py < 0 || py > tcurr.size().height)
          continue;
        for (auto ox = -kradius; ox <= kradius; ++ox) {
          int px = x + ox;
          if (px < 0 || px > tcurr.size().width)
            continue;
          k += 1.0;
          const auto pb = cv::Point2d(px, py);
          sigma += tcurr.at<double>(pb) * Ws(pa, pb, kradius) *
                   Wm(pa, pb, grad) * Wd(pa, pb, tcurr);
        }
      }
      tnew.at<double>(pa) = (k > 0.1) ? sigma / k : 0.0;
    }
  }
  tcurr = tnew;
}

cv::Mat coherentLines(const cv::Mat &img, const int kernel_radius = 5,
                      const int etf_iterations = 3) {
  cv::Mat gray;
  cv::cvtColor(img, gray, CV_BGR2GRAY);

  cv::Mat gx, gy, gm, gt, gmnorm;
  cv::Sobel(gray, gx, CV_64F, 1, 0, 3);
  cv::Sobel(gray, gy, CV_64F, 0, 1, 3);
  cv::magnitude(gx, gy, gm);
  cv::normalize(gm, gt, 1.0, 0.0, cv::NORM_INF);
  gt.convertTo(gmnorm, CV_64FC1);

  cv::imshow("Grad", gmnorm);
  cv::waitKey(100);

  cv::Mat etf;
  gmnorm.copyTo(etf);
  for (auto i = 0; i < etf_iterations; ++i)
    ETFIteration(etf, gmnorm, kernel_radius);

  cv::Mat etf_vis;
  cv::normalize(etf, etf_vis, 1.0, 0.0, cv::NORM_MINMAX);
  cv::imshow("ETF", etf_vis);

  return etf;
}

int main(int argc, char **argv) {
  if (argc != 2) {
    std::cout << argv[0] << " <path_to_image>" << std::endl;
    return 1;
  }

  auto img = cv::imread(argv[1]);
  cv::imshow("input", img);
  cv::waitKey(100);

  coherentLines(img);
  cv::waitKey(0);

  return 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CppUnitTest.h"

#include "PointerDataType.h"
#include "HelperFunction.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;
using namespace FTL;

namespace FTLTest
{
	TEST_CLASS(PointerTest)
	{
	public:
		TEST_METHOD(PointerTest1)
		{
			unique_ptr<int> ptpt;
			int a = 3;
			int* pA = &a;
			PointerDataType<int*> t1 = &a;
			int*& ppA = pA;
			*ppA;
			decltype((*ppA)) pppA = *pA;
			Log(*t1);
		}
	};
}<commit_msg>Pointer test added<commit_after>#include "stdafx.h"
#include "CppUnitTest.h"

#include "PointerDataType.h"
#include "HelperFunction.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace std;
using namespace FTL;

namespace FTLTest
{
	TEST_CLASS(PointerTest)
	{
	public:
		TEST_METHOD(PointerTest1)
		{
			int a = 3;
			int* pA = &a;
			PointerDataType<decltype(pA)> t1 = &a;

			Assert::AreEqual(pA, t1);
			Assert::AreEqual(&a, t1);

			Assert::AreEqual(3, a);
			Assert::AreEqual(3, *pA);
			Assert::AreEqual(3, *t1);

			a = 4;

			Assert::AreEqual(4, a);
			Assert::AreEqual(4, *pA);
			Assert::AreEqual(4, *t1);

			*pA = 5;

			Assert::AreEqual(5, a);
			Assert::AreEqual(5, *pA);
			Assert::AreEqual(5, *t1);

			*t1 = 6;

			Assert::AreEqual(6, a);
			Assert::AreEqual(6, *pA);
			Assert::AreEqual(6, *t1);
		}

		TEST_METHOD(PointerTest2)
		{
			int* pA = new int(3);
			unique_ptr<int> upt(pA);

			Assert::AreEqual(3, *upt);

			PointerDataType<decltype(upt)> pt;
			pt.swap(upt);

			Assert::AreEqual(true, std::is_same<decltype(upt), decltype(pt)>::value);
			Assert::AreEqual(true, upt.get() == nullptr);
			Assert::AreEqual(3, *pt);
			Assert::AreEqual(pA, pt.get());

			*pA = 4;

			Assert::AreEqual(4, *pA);
			Assert::AreEqual(4, *pt);

			*pt = 5;

			Assert::AreEqual(5, *pA);
			Assert::AreEqual(5, *pt);
		}
	};
}<|endoftext|>


<commit_before>/*
 *  Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Stephen F. Booth <me@sbooth.org>
 *  All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    - Neither the name of Stephen F. Booth nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <taglib/mpegfile.h>
#include <taglib/mpegproperties.h>
#include <taglib/xingheader.h>

#include "MP3Metadata.h"
#include "CreateDisplayNameForURL.h"
#include "AddID3v1TagToDictionary.h"
#include "AddID3v2TagToDictionary.h"
#include "SetID3v2TagFromMetadata.h"
#include "AddAudioPropertiesToDictionary.h"

#pragma mark Static Methods

CFArrayRef MP3Metadata::CreateSupportedFileExtensions()
{
	CFStringRef supportedExtensions [] = { CFSTR("mp3") };
	return CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void **>(supportedExtensions), 1, &kCFTypeArrayCallBacks);
}

CFArrayRef MP3Metadata::CreateSupportedMIMETypes()
{
	CFStringRef supportedMIMETypes [] = { CFSTR("audio/mpeg") };
	return CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void **>(supportedMIMETypes), 1, &kCFTypeArrayCallBacks);
}

bool MP3Metadata::HandlesFilesWithExtension(CFStringRef extension)
{
	if(NULL == extension)
		return false;

	if(kCFCompareEqualTo == CFStringCompare(extension, CFSTR("mp3"), kCFCompareCaseInsensitive))
		return true;

	return false;
}

bool MP3Metadata::HandlesMIMEType(CFStringRef mimeType)
{
	if(NULL == mimeType)
		return false;

	if(kCFCompareEqualTo == CFStringCompare(mimeType, CFSTR("audio/mpeg"), kCFCompareCaseInsensitive))
		return true;

	return false;
}

#pragma mark Creation and Destruction

MP3Metadata::MP3Metadata(CFURLRef url)
	: AudioMetadata(url)
{}

MP3Metadata::~MP3Metadata()
{}

#pragma mark Functionality

bool MP3Metadata::ReadMetadata(CFErrorRef *error)
{
	// Start from scratch
	CFDictionaryRemoveAllValues(mMetadata);
	CFDictionaryRemoveAllValues(mChangedMetadata);

	UInt8 buf [PATH_MAX];
	if(!CFURLGetFileSystemRepresentation(mURL, false, buf, PATH_MAX))
		return false;

	TagLib::MPEG::File file(reinterpret_cast<const char *>(buf), TagLib::ID3v2::FrameFactory::instance(), true);

	if(!file.isValid()) {
		if(NULL != error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Not a MPEG file"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MP3"));

	if(file.audioProperties()) {
		TagLib::MPEG::Properties *properties = file.audioProperties();
		AddAudioPropertiesToDictionary(mMetadata, properties);

		// TODO: Is this too much information?
#if 0
		switch(properties->version()) {
			case TagLib::MPEG::Header::Version1:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer I"));		break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer III"));	break;
				}
				break;
			case TagLib::MPEG::Header::Version2:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer I"));		break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer III"));	break;
				}
				break;
			case TagLib::MPEG::Header::Version2_5:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer I"));	break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer III"));	break;
				}
				break;
		}
#endif

		if(properties->xingHeader() && properties->xingHeader()->totalFrames()) {
			TagLib::uint frames = properties->xingHeader()->totalFrames();
			CFNumberRef totalFrames = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &frames);
			CFDictionaryAddValue(mMetadata, kPropertiesTotalFramesKey, totalFrames);
			CFRelease(totalFrames), totalFrames = NULL;
		}
	}

	if(file.ID3v1Tag())
		AddID3v1TagToDictionary(mMetadata, file.ID3v1Tag());

	if(file.ID3v2Tag())
		AddID3v2TagToDictionary(mMetadata, file.ID3v2Tag());

	return true;
}

bool MP3Metadata::WriteMetadata(CFErrorRef *error)
{
	UInt8 buf [PATH_MAX];
	if(!CFURLGetFileSystemRepresentation(mURL, false, buf, PATH_MAX))
		return false;

	TagLib::MPEG::File file(reinterpret_cast<const char *>(buf), false, false);

	if(!file.isValid()) {
		if(error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Not a MPEG file"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	SetID3v2TagFromMetadata(*this, file.ID3v2Tag(true));

	if(!file.save()) {
		if(error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Unable to write metadata"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	MergeChangedMetadataIntoMetadata();

	return true;
}
<commit_msg>Ensure MP3 files are opened read-only in ReadMetadata()<commit_after>/*
 *  Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Stephen F. Booth <me@sbooth.org>
 *  All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *    - Neither the name of Stephen F. Booth nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <taglib/mpegfile.h>
#include <taglib/mpegproperties.h>
#include <taglib/xingheader.h>

#include "MP3Metadata.h"
#include "CreateDisplayNameForURL.h"
#include "AddID3v1TagToDictionary.h"
#include "AddID3v2TagToDictionary.h"
#include "SetID3v2TagFromMetadata.h"
#include "AddAudioPropertiesToDictionary.h"

#pragma mark Static Methods

CFArrayRef MP3Metadata::CreateSupportedFileExtensions()
{
	CFStringRef supportedExtensions [] = { CFSTR("mp3") };
	return CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void **>(supportedExtensions), 1, &kCFTypeArrayCallBacks);
}

CFArrayRef MP3Metadata::CreateSupportedMIMETypes()
{
	CFStringRef supportedMIMETypes [] = { CFSTR("audio/mpeg") };
	return CFArrayCreate(kCFAllocatorDefault, reinterpret_cast<const void **>(supportedMIMETypes), 1, &kCFTypeArrayCallBacks);
}

bool MP3Metadata::HandlesFilesWithExtension(CFStringRef extension)
{
	if(NULL == extension)
		return false;

	if(kCFCompareEqualTo == CFStringCompare(extension, CFSTR("mp3"), kCFCompareCaseInsensitive))
		return true;

	return false;
}

bool MP3Metadata::HandlesMIMEType(CFStringRef mimeType)
{
	if(NULL == mimeType)
		return false;

	if(kCFCompareEqualTo == CFStringCompare(mimeType, CFSTR("audio/mpeg"), kCFCompareCaseInsensitive))
		return true;

	return false;
}

#pragma mark Creation and Destruction

MP3Metadata::MP3Metadata(CFURLRef url)
	: AudioMetadata(url)
{}

MP3Metadata::~MP3Metadata()
{}

#pragma mark Functionality

bool MP3Metadata::ReadMetadata(CFErrorRef *error)
{
	// Start from scratch
	CFDictionaryRemoveAllValues(mMetadata);
	CFDictionaryRemoveAllValues(mChangedMetadata);

	UInt8 buf [PATH_MAX];
	if(!CFURLGetFileSystemRepresentation(mURL, false, buf, PATH_MAX))
		return false;

	TagLib::IOStream *stream = new TagLib::FileStream(reinterpret_cast<const char *>(buf), true);
	TagLib::MPEG::File file(stream, TagLib::ID3v2::FrameFactory::instance());

	if(!file.isValid()) {
		if(NULL != error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Not a MPEG file"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MP3"));

	if(file.audioProperties()) {
		TagLib::MPEG::Properties *properties = file.audioProperties();
		AddAudioPropertiesToDictionary(mMetadata, properties);

		// TODO: Is this too much information?
#if 0
		switch(properties->version()) {
			case TagLib::MPEG::Header::Version1:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer I"));		break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-1 Layer III"));	break;
				}
				break;
			case TagLib::MPEG::Header::Version2:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer I"));		break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2 Layer III"));	break;
				}
				break;
			case TagLib::MPEG::Header::Version2_5:
				switch(properties->layer()) {
					case 1:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer I"));	break;
					case 2:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer II"));	break;
					case 3:		CFDictionarySetValue(mMetadata, kPropertiesFormatNameKey, CFSTR("MPEG-2.5 Layer III"));	break;
				}
				break;
		}
#endif

		if(properties->xingHeader() && properties->xingHeader()->totalFrames()) {
			TagLib::uint frames = properties->xingHeader()->totalFrames();
			CFNumberRef totalFrames = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &frames);
			CFDictionaryAddValue(mMetadata, kPropertiesTotalFramesKey, totalFrames);
			CFRelease(totalFrames), totalFrames = NULL;
		}
	}

	if(file.ID3v1Tag())
		AddID3v1TagToDictionary(mMetadata, file.ID3v1Tag());

	if(file.ID3v2Tag())
		AddID3v2TagToDictionary(mMetadata, file.ID3v2Tag());

	return true;
}

bool MP3Metadata::WriteMetadata(CFErrorRef *error)
{
	UInt8 buf [PATH_MAX];
	if(!CFURLGetFileSystemRepresentation(mURL, false, buf, PATH_MAX))
		return false;

	TagLib::IOStream *stream = new TagLib::FileStream(reinterpret_cast<const char *>(buf));
	TagLib::MPEG::File file(stream, TagLib::ID3v2::FrameFactory::instance(), false);

	if(!file.isValid()) {
		if(error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Not a MPEG file"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	SetID3v2TagFromMetadata(*this, file.ID3v2Tag(true));

	if(!file.save()) {
		if(error) {
			CFMutableDictionaryRef errorDictionary = CFDictionaryCreateMutable(kCFAllocatorDefault,
																			   32,
																			   &kCFTypeDictionaryKeyCallBacks,
																			   &kCFTypeDictionaryValueCallBacks);

			CFStringRef displayName = CreateDisplayNameForURL(mURL);
			CFStringRef errorString = CFStringCreateWithFormat(kCFAllocatorDefault,
															   NULL,
															   CFCopyLocalizedString(CFSTR("The file “%@” is not a valid MPEG file."), ""),
															   displayName);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedDescriptionKey,
								 errorString);

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedFailureReasonKey,
								 CFCopyLocalizedString(CFSTR("Unable to write metadata"), ""));

			CFDictionarySetValue(errorDictionary,
								 kCFErrorLocalizedRecoverySuggestionKey,
								 CFCopyLocalizedString(CFSTR("The file's extension may not match the file's type."), ""));

			CFRelease(errorString), errorString = NULL;
			CFRelease(displayName), displayName = NULL;

			*error = CFErrorCreate(kCFAllocatorDefault,
								   AudioMetadataErrorDomain,
								   AudioMetadataInputOutputError,
								   errorDictionary);

			CFRelease(errorDictionary), errorDictionary = NULL;
		}

		return false;
	}

	MergeChangedMetadataIntoMetadata();

	return true;
}
<|endoftext|>


<commit_before>#ifndef _MZ_NET_ADDRESS_HPP_
#define _MZ_NET_ADDRESS_HPP_

#include "Metazion/Net/NetInclude.hpp"

DECL_NAMESPACE_MZ_NET_BEGIN

struct Address {
    UINT32 m_ip = 0;
    UINT16 m_port = 0;
};

DECL_NAMESPACE_MZ_NET_END

#endif // _MZ_NET_ADDRESS_HPP_
<commit_msg>Fix some issues.<commit_after>#ifndef _MZ_NET_ADDRESS_HPP_
#define _MZ_NET_ADDRESS_HPP_

#include "Metazion/Net/NetInclude.hpp"

DECL_NAMESPACE_MZ_NET_BEGIN

struct Address {
    uint32_t m_ip = 0;
    uint16_t m_port = 0;
};

DECL_NAMESPACE_MZ_NET_END

#endif // _MZ_NET_ADDRESS_HPP_
<|endoftext|>