#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#include "ppport.h"

#define CHECK_INDEX(idx, min, max, ret) if(idx < min || idx > max) {	\
		croak("Index not in range [" IVdf "," IVdf "]", (IV)(min), (IV)(max)); \
		return ret;														\
	}

typedef struct {
	IV n;
	IV* t;
} bit;

bit* bit_create(IV len) {
	if(len < 1){
		croak("Length less than 1");
		return 0;
	}
	len++;
	bit *ret;
	Newx(ret, 1, bit);
	ret->n = len;
	Newxz(ret->t, len, IV);
	return ret;
}

void bit_free(bit *b) {
	Safefree(b->t);
	Safefree(b);
}

IV bit_query(bit *b, IV idx) {
	CHECK_INDEX(idx, 0, b->n - 1, 0);
	IV ret = 0;
	while(idx)
		ret += b->t[idx], idx -= idx & -idx;
	return ret;
}

void bit_update(bit *b, IV idx, IV value) {
	CHECK_INDEX(idx, 0, b->n - 1, );
	while(idx < b->n)
		b->t[idx] += value, idx += idx & -idx;
}

void bit_clear(bit *b) {
	Zero(b->t, b->n, IV);
}

typedef struct {
	IV n, m;
	IV* t;
} bit2d;

bit2d* bit2d_create(IV n, IV m) {
	if(n < 1 || m < 1){
		croak("A dimension is less than 1");
		return 0;
	}
	n++, m++;
	bit2d *ret;
	Newx(ret, 1, bit2d);
	ret->n = n;
	ret->m = m;
	Newxz(ret->t, n * m, IV);
	return ret;
}

void bit2d_free(bit2d *b) {
	Safefree(b->t);
	Safefree(b);
}

IV bit2d_query(bit2d *b, IV i1, IV i2) {
	CHECK_INDEX(i1, 1, b->n - 1, 0);
	CHECK_INDEX(i2, 1, b->m - 1, 0);
	if(i1 > b->n || i1 < 1) {
		croak("Index 1 not in range [1," IVdf "]", b->n);
		return 0;
	}
	if(i2 > b->m || i2 < 1) {
		croak("Index 2 not in range [1," IVdf "]", b->m);
		return 0;
	}
	IV ret = 0, i2c = i2;
	while(i1) {
		i2 = i2c;
		while(i2)
			ret += b->t[i1 * b->m + i2], i2 -= i2 & -i2;
		i1 -= i1 & -i1;
	}
	return ret;
}

void bit2d_update(bit2d *b, IV i1, IV i2, IV value) {
	CHECK_INDEX(i1, 1, b->n - 1, );
	CHECK_INDEX(i2, 1, b->m - 1, );
	IV i2c = i2;
	while(i1 < b->n) {
		i2 = i2c;
		while(i2 < b->m)
			b->t[i1 * b->m + i2] += value, i2 += i2 & -i2;
		i1 += i1 & -i1;
	}
}

void bit2d_clear(bit2d *b) {
	Zero(b->t, b->n * b->m, IV);
}

typedef bit *Algorithm__BIT__XS;
typedef bit2d *Algorithm__BIT2D__XS;

MODULE = Algorithm::BIT::XS		PACKAGE = Algorithm::BIT::XS		PREFIX = bit_

PROTOTYPES: ENABLE

Algorithm::BIT::XS bit_create(IV len);

void bit_free(Algorithm::BIT::XS b);
ALIAS:
    DESTROY = 1

IV bit_query(Algorithm::BIT::XS b, IV idx);

void bit_update(Algorithm::BIT::XS b, IV idx, IV value);

void bit_clear(Algorithm::BIT::XS b);

MODULE = Algorithm::BIT::XS		PACKAGE = Algorithm::BIT2D::XS		PREFIX = bit2d_

PROTOTYPES: ENABLE

Algorithm::BIT2D::XS bit2d_create(IV n, IV m);

void bit2d_free(Algorithm::BIT2D::XS b);
ALIAS:
    DESTROY = 1

IV bit2d_query(Algorithm::BIT2D::XS b, IV i1, IV i2);

void bit2d_update(Algorithm::BIT2D::XS b, IV i1, IV i2, IV value);

void bit2d_clear(Algorithm::BIT2D::XS b);