<commit_before>#ifndef HMLIB_LATICES_BLOCKLATTICE_INC
#define HMLIB_LATICES_BLOCKLATTICE_INC 100
#include<vector>
#include<functional>
#include<algorithm>
#include"../algorithm/algorithm.hpp"
#include"utility.hpp"
#include"exceptions.hpp"
#include"indexer.hpp"
#include"iterator.hpp"
#include"locator.hpp"
#include"lattice.hpp"
namespace hmLib {
	template<typename T, unsigned int dim_>
	struct block_lattice {
	private:
		using this_type = block_lattice<T, dim_>;
	public:
		static constexpr unsigned int dim() { return dim_; }
		using point_type = lattices::point_type<dim_>;
		using extent_type = lattices::extent_type<dim_>;
		using size_type = lattices::size_type;
		using diff_type = lattices::diff_type;
		using index_type = lattices::index_type;
		using indexer = lattices::indexer<dim_>;
	public:
		using value_type = typename std::decay<T>::type;
		using reference = value_type&;
		using const_reference = const value_type&;
		using pointer = value_type*;
		using const_pointer = const value_type*;
	public:
		struct block {
			friend struct block_lattice<T, dim_>;
			using container = std::vector<value_type>;
			using iterator = typename container::iterator;
			using const_iterator = typename container::const_iterator;
		public:
			block() = default;
			block(point_type Pos_, indexer Indexer_, unsigned int Size_):Pos(Pos_), Indexer(Indexer_), Data(Size_, 0) {}
		public:
			iterator begin() { return Data.begin(); }
			iterator end() { return Data.end(); }
			const_iterator begin()const { return cbegin(); }
			const_iterator end()const { return cend(); }
			const_iterator cbegin()const { return Data.begin(); }
			const_iterator cend()const { return Data.end(); }
			reference at(point_type Pos_) {
				return Data[Indexer.torus_index(Pos_)];
			}
			const_reference at(point_type Pos_)const {
				return Data[Indexer.torus_index(Pos_)];
			}
			template<typename... others>
			reference at(index_type Pos_, others... Others_) {return at(lattices::point(Pos_, Others_...));}
			template<typename... others>
			const_reference at(index_type Pos_, others... Others_)const { return at(lattices::point(Pos_, Others_...)); }
			reference ref(point_type Pos_) {
				return at(Pos_);
			}
			const_reference ref(point_type Pos_)const {
				return at(Pos_);
			}
			template<typename... others>
			reference ref(index_type Pos_, others... Others_) { return ref(lattices::point(Pos_, Others_...)); }
			template<typename... others>
			const_reference ref(index_type Pos_, others... Others_)const { return ref(lattices::point(Pos_, Others_...)); }
			reference operator[](point_type Pos_) {return ref(Pos_);}
			const_reference operator[](point_type Pos_)const {return ref(Pos_);}
		public:
			point_type point()const { return Pos; }
			point_type point(const_iterator Itr)const { return Pos + Indexer.calc_point(std::distance(begin(),Itr)); }
			//!Get point_type BlockNum
			const extent_type& extent()const { return Indexer.extent(); }
			size_type lattice_size()const { return Indexer.lattice_size(); }
			//!Return true if the given point is inclueded incide of this block.
			bool inside(point_type Point_)const {
				for(unsigned int i = 0; i<dim_; ++i) {
					if( !(Pos[i]<=Point_[i] && Point_[i]<Pos[i]+static_cast<index_type>(Indexer.extent()[i])) )return false;
				}
				return true;
			}
			//!Convert from index to point
			point_type index_to_point(index_type Index_)const { return Indexer.point(Index_); }
			//!Convert from point to index
			index_type point_to_index(point_type Point_)const { return Indexer.index(Point_); }
			//!Return reference of the elemtn at the given Index with checking out-of-range, i.e., at(Pos) == index_at(point_to_index(Pos));
			reference index_at(index_type Index_) { return Data.at(Index_); }
			//!Return reference of the elemtn at the given Index with checking out-of-range, i.e., at(Pos) == index_at(point_to_index(Pos));
			const_reference index_at(index_type Index_)const { return Data.at(Index_); }
			//!Return reference of the elemtn at the given Index without checking out-of-range, i.e., ref(Pos) == index_ref(point_to_index(Pos));
			reference index_ref(index_type Index_) { return Data[Index_]; }
			//!Return reference of the elemtn at the given Index without checking out-of-range, i.e., ref(Pos) == index_ref(point_to_index(Pos));
			const_reference index_ref(index_type Index_)const { return Data[Index_]; }
		private:
			void assign(point_type Pos_, indexer Indexer_, unsigned int Size_) {
				Pos = Pos_;
				Indexer = Indexer_;
				Data.assign(Size_,0);
			}
		private:
			point_type Pos;
			indexer Indexer;
			container Data;
		};
	private:
		using block_container = std::vector<block>;
	public:
		using block_iterator = typename block_container::iterator;
		using block_const_iterator = typename block_container::const_iterator;
		using element_iterator = typename block::iterator;
		using element_const_iterator = typename block::const_iterator;
		struct const_iterator {
		public:
			using value_type = typename this_type::value_type;
			using difference_type = int;
			using reference = typename this_type::const_reference;
			using pointer = typename this_type::const_pointer;
			using iterator_category = std::random_access_iterator_tag;
		public:
			const_iterator() = default;
			const_iterator(block_const_iterator BItr_, element_const_iterator Itr_):BItr(BItr_), Itr(Itr_) {}
		public:
			reference operator*() {
				return Itr.operator*();
			}
			reference operator[](difference_type n) {
				return (*this + n).operator*();
			}
			pointer operator->() {
				return Itr.operator->();
			}
			const_iterator& operator++() {
				++Itr;
				if(Itr == BItr->end()) {
					++BItr;
					Itr = BItr->begin();
				}
				return *this;
			}
			const_iterator operator++(int) {
				const_iterator Ans = *this;
				operator++();
				return Ans;
			}
			const_iterator& operator--() {
				if(Itr == BItr->begin()) {
					--BItr;
					Itr = BItr->end();
				}
				--Itr;
				return *this;
			}
			const_iterator operator--(int) {
				const_iterator Ans = *this;
				operator--();
				return Ans;
			}
			const_iterator& operator+=(difference_type n) {
				if(n<0)return operator-=(-n);

				if(n < std::distance(Itr, BItr->end())) {
					Itr += n;
				}else{
					auto BlockSize = BItr->size();
					n -= std::distance(Itr, BItr->end());
					++BItr;

					BItr += n/BlockSize;
					Itr = std::next(BItr->begin(), n%BlockSize);
				}
				return *this;
			}
			const_iterator& operator-=(difference_type n) {
				if(n<0)return operator+=(-n);

				if(n < std::distance(BItr->begin(), Itr)) {
					Itr -= n;
				} else {
					n -= std::distance(BItr->begin(), Itr);
					--BItr;
					auto BlockSize = BItr->size();

					BItr -= n/BlockSize;
					Itr = std::next(BItr->end()-1, -(n%BlockSize));
				}
				return *this;
			}
			friend const_iterator operator+(const const_iterator& v, difference_type n) {
				auto v2 = v;
				v2 += n;
				return v2;
			}
			friend const_iterator operator+(difference_type n, const const_iterator& v) {
				return v+n;
			}
			friend const_iterator operator-(const const_iterator& v, difference_type n) {
				auto v2 = v;
				v2 -= n;
				return v2;
			}
			friend difference_type operator-(const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr > v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v2.Bitr->size());
				else if(v1.BItr < v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v1.Bitr->size());
				else return v1.Itr - v2.Itr;
			}
			friend bool operator==(const const_iterator& v1, const const_iterator&  v2) {
				return v1.BItr == v2.BItr && v1.Itr == v2.Itr;
			}
			friend bool operator!=(const const_iterator&  v1, const const_iterator&  v2) {
				return v1.BItr != v2.BItr || v1.Itr != v2.Itr;
			}
			friend bool operator< (const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr < v2.Itr;
			}
			friend bool operator<=(const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr <= v2.Itr;
			}
			friend bool operator> (const const_iterator& v1, const const_iterator&  v2) {
				return operator<(v2, v1);
			}
			friend bool operator>=(const const_iterator& v1, const const_iterator&  v2) {
				return operator<=(v2, v1);
			}
		public:
			point_type point()const { return BItr->point(Itr); }
			block_const_iterator block_itr() { return BItr; }
			element_const_iterator element_itr() { return Itr; }
		private:
			block_const_iterator BItr;
			element_const_iterator Itr;
		};
		struct iterator {
		public:
			using value_type = typename this_type::value_type;
			using difference_type = int;
			using reference = typename this_type::reference;
			using pointer = typename this_type::pointer;
			using iterator_category = std::random_access_iterator_tag;
		public:
			iterator() = default;
			iterator(block_iterator BItr_, element_iterator Itr_):BItr(BItr_),Itr(Itr_){}
			operator const_iterator() { return const_iterator(BItr, Itr); }
		public:
			reference operator*() {
				return Itr.operator*();
			}
			reference operator[](difference_type n) {
				return (*this + n).operator*();
			}
			pointer operator->() {
				return Itr.operator->();
			}
			iterator& operator++() {
				++Itr;
				if(Itr == BItr->end()) {
					++BItr;
					Itr = BItr->begin();
				}
				return *this;
			}
			iterator operator++(int) {
				iterator Ans = *this;
				operator++();
				return Ans;
			}
			iterator& operator--() {
				if(Itr == BItr->begin()) {
					--BItr;
					Itr = BItr->end();
				}
				--Itr;
				return *this;
			}
			iterator operator--(int) {
				iterator Ans = *this;
				operator--();
				return Ans;
			}
			iterator& operator+=(difference_type n) {
				if(n<0)return operator-=(-n);

				if(n < std::distance(Itr, BItr->end())) {
					Itr += n;
				} else {
					auto BlockSize = BItr->size();
					n -= std::distance(Itr, BItr->end());
					++BItr;

					BItr += n/BlockSize;
					Itr = std::next(BItr->begin(), n%BlockSize);
				}
				return *this;
			}
			iterator& operator-=(difference_type n) {
				if(n<0)return operator+=(-n);

				if(n < std::distance(BItr->begin(), Itr)) {
					Itr -= n;
				} else {
					n -= std::distance(BItr->begin(), Itr);
					--BItr;
					auto BlockSize = BItr->size();

					BItr -= n/BlockSize;
					Itr = std::next(BItr->end()-1, -(n%BlockSize));
				}
				return *this;
			}
			friend iterator operator+(const iterator& v, difference_type n) {
				auto v2 = v;
				v2 += n;
				return v2;
			}
			friend iterator operator+(difference_type n, const iterator& v) {
				return v+n;
			}
			friend iterator operator-(const iterator& v, difference_type n) {
				auto v2 = v;
				v2 -= n;
				return v2;
			}
			friend difference_type operator-(const iterator& v1, const iterator&  v2) {
				if(v1.BItr > v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v2.Bitr->size());
				else if(v1.BItr < v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v1.Bitr->size());
				else return v1.Itr - v2.Itr;
			}
			friend bool operator==(const iterator& v1, const iterator& v2) {
				return v1.BItr == v2.BItr && v1.Itr == v2.Itr;
			}
			friend bool operator!=(const iterator& v1, const iterator& v2) {
				return v1.BItr != v2.BItr || v1.Itr != v2.Itr;
			}
			friend bool operator< (const iterator& v1, const iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr < v2.Itr;
			}
			friend bool operator<=(const iterator& v1, const iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr <= v2.Itr;
			}
			friend bool operator> (const iterator& v1, const iterator&  v2) {
				return operator<(v2, v1);
			}
			friend bool operator>=(const iterator& v1, const iterator&  v2) {
				return operator<=(v2, v1);
			}
		public:
			point_type point()const { return BItr->point(Itr); }
			block_iterator block_itr() { return BItr; }
			element_iterator element_itr() { return Itr; }
		private:
			block_iterator BItr;
			element_iterator Itr;
		};
	public:
		block_lattice()noexcept:block_lattice(extent_type(10)) {}
		explicit block_lattice(extent_type BlockExtent)noexcept
			: Blocks()
			, Indexer(BlockExtent)
			, BlockNum(0)
			, HintPos(0){
			BlockSize = Indexer.lattice_size();
			Blocks.push_back(block(point_type(0), Indexer, BlockSize));
		}
		template<typename... others>
		explicit block_lattice(std::size_t Size_, others... Others_)noexcept: block_lattice(extent_type{ Size_,static_cast<std::size_t>(Others_)... }) {}
	public:
		bool empty()const{ return block_num()==0; }
		void clear() { BlockNum = 0; HintPos = 0; }
		std::size_t size()const { return block_num()*block_size(); }
		void block_resize(extent_type BlockExtent){
			if(empty()) {
				Indexer.resize(BlockExtent);
				BlockSize = Indexer.lattice_size();
			} else {
				this_type New(BlockExtent);
				auto End = end();
				for(auto Itr = begin(); Itr!=End; ++Itr) {
					New[Itr.point()] = *Itr;
				}
				*this = std::move(New);
			}
		}
		template<typename... others>
		void block_resize(std::size_t Size_, others... Others_) {
			block_resize(extent_type{ Size_,static_cast<std::size_t>(Others_)... });
		}
	public://manipulation related to block
		//!Get block extent
		extent_type block_extent()const { return Indexer.extent(); }
		//!Get block size
		size_type block_size()const { return BlockSize; }
		//!Get block number
		size_type block_num()const { return BlockNum; }
		//!Get block access iterator at begin
		block_iterator block_begin() { return Blocks.begin(); }
		//!Get block access iterator at begin
		block_const_iterator block_begin()const { return Blocks.begin(); }
		//!Get block access iterator at end
		block_iterator block_end() { return Blocks.begin()+BlockNum; }
		//!Get block access iterator at end
		block_const_iterator block_end()const { return Blocks.begin()+BlockNum; }
		//!Remove block
		void block_erase(block_iterator Itr) {
			if(Itr == block_end())return;
			if(std::distance(block_begin(), Itr)<=HintPos) {
				--HintPos;
			}
			std::rotate(Itr, Itr+1, block_end());
			--BlockNum;
		}
		//!Remove block
		template<typename block_condition_>
		void block_erase_if(block_condition_ BlockCondition){
			BlockNum = std::distance(
				block_begin(),
				hmLib::swap_remove_if(block_begin(), block_end(), std::forward<block_condition_>(BlockCondition))
			);
			HintPos = 0;
		}
		template<typename element_condition_><commit_msg>Hint is now indicate BlockNum when it is difficult to estimate<commit_after>#ifndef HMLIB_LATICES_BLOCKLATTICE_INC
#define HMLIB_LATICES_BLOCKLATTICE_INC 100
#include<vector>
#include<functional>
#include<algorithm>
#include"../algorithm/algorithm.hpp"
#include"utility.hpp"
#include"exceptions.hpp"
#include"indexer.hpp"
#include"iterator.hpp"
#include"locator.hpp"
#include"lattice.hpp"
namespace hmLib {
	template<typename T, unsigned int dim_>
	struct block_lattice {
	private:
		using this_type = block_lattice<T, dim_>;
	public:
		static constexpr unsigned int dim() { return dim_; }
		using point_type = lattices::point_type<dim_>;
		using extent_type = lattices::extent_type<dim_>;
		using size_type = lattices::size_type;
		using diff_type = lattices::diff_type;
		using index_type = lattices::index_type;
		using indexer = lattices::indexer<dim_>;
	public:
		using value_type = typename std::decay<T>::type;
		using reference = value_type&;
		using const_reference = const value_type&;
		using pointer = value_type*;
		using const_pointer = const value_type*;
	public:
		struct block {
			friend struct block_lattice<T, dim_>;
			using container = std::vector<value_type>;
			using iterator = typename container::iterator;
			using const_iterator = typename container::const_iterator;
		public:
			block() = default;
			block(point_type Pos_, indexer Indexer_, unsigned int Size_):Pos(Pos_), Indexer(Indexer_), Data(Size_, 0) {}
		public:
			iterator begin() { return Data.begin(); }
			iterator end() { return Data.end(); }
			const_iterator begin()const { return cbegin(); }
			const_iterator end()const { return cend(); }
			const_iterator cbegin()const { return Data.begin(); }
			const_iterator cend()const { return Data.end(); }
			reference at(point_type Pos_) {
				return Data[Indexer.torus_index(Pos_)];
			}
			const_reference at(point_type Pos_)const {
				return Data[Indexer.torus_index(Pos_)];
			}
			template<typename... others>
			reference at(index_type Pos_, others... Others_) {return at(lattices::point(Pos_, Others_...));}
			template<typename... others>
			const_reference at(index_type Pos_, others... Others_)const { return at(lattices::point(Pos_, Others_...)); }
			reference ref(point_type Pos_) {
				return at(Pos_);
			}
			const_reference ref(point_type Pos_)const {
				return at(Pos_);
			}
			template<typename... others>
			reference ref(index_type Pos_, others... Others_) { return ref(lattices::point(Pos_, Others_...)); }
			template<typename... others>
			const_reference ref(index_type Pos_, others... Others_)const { return ref(lattices::point(Pos_, Others_...)); }
			reference operator[](point_type Pos_) {return ref(Pos_);}
			const_reference operator[](point_type Pos_)const {return ref(Pos_);}
		public:
			point_type point()const { return Pos; }
			point_type point(const_iterator Itr)const { return Pos + Indexer.calc_point(std::distance(begin(),Itr)); }
			//!Get point_type BlockNum
			const extent_type& extent()const { return Indexer.extent(); }
			size_type lattice_size()const { return Indexer.lattice_size(); }
			//!Return true if the given point is inclueded incide of this block.
			bool inside(point_type Point_)const {
				for(unsigned int i = 0; i<dim_; ++i) {
					if( !(Pos[i]<=Point_[i] && Point_[i]<Pos[i]+static_cast<index_type>(Indexer.extent()[i])) )return false;
				}
				return true;
			}
			//!Convert from index to point
			point_type index_to_point(index_type Index_)const { return Indexer.point(Index_); }
			//!Convert from point to index
			index_type point_to_index(point_type Point_)const { return Indexer.index(Point_); }
			//!Return reference of the elemtn at the given Index with checking out-of-range, i.e., at(Pos) == index_at(point_to_index(Pos));
			reference index_at(index_type Index_) { return Data.at(Index_); }
			//!Return reference of the elemtn at the given Index with checking out-of-range, i.e., at(Pos) == index_at(point_to_index(Pos));
			const_reference index_at(index_type Index_)const { return Data.at(Index_); }
			//!Return reference of the elemtn at the given Index without checking out-of-range, i.e., ref(Pos) == index_ref(point_to_index(Pos));
			reference index_ref(index_type Index_) { return Data[Index_]; }
			//!Return reference of the elemtn at the given Index without checking out-of-range, i.e., ref(Pos) == index_ref(point_to_index(Pos));
			const_reference index_ref(index_type Index_)const { return Data[Index_]; }
		private:
			void assign(point_type Pos_, indexer Indexer_, unsigned int Size_) {
				Pos = Pos_;
				Indexer = Indexer_;
				Data.assign(Size_,0);
			}
		private:
			point_type Pos;
			indexer Indexer;
			container Data;
		};
	private:
		using block_container = std::vector<block>;
	public:
		using block_iterator = typename block_container::iterator;
		using block_const_iterator = typename block_container::const_iterator;
		using element_iterator = typename block::iterator;
		using element_const_iterator = typename block::const_iterator;
		struct const_iterator {
		public:
			using value_type = typename this_type::value_type;
			using difference_type = int;
			using reference = typename this_type::const_reference;
			using pointer = typename this_type::const_pointer;
			using iterator_category = std::random_access_iterator_tag;
		public:
			const_iterator() = default;
			const_iterator(block_const_iterator BItr_, element_const_iterator Itr_):BItr(BItr_), Itr(Itr_) {}
		public:
			reference operator*() {
				return Itr.operator*();
			}
			reference operator[](difference_type n) {
				return (*this + n).operator*();
			}
			pointer operator->() {
				return Itr.operator->();
			}
			const_iterator& operator++() {
				++Itr;
				if(Itr == BItr->end()) {
					++BItr;
					Itr = BItr->begin();
				}
				return *this;
			}
			const_iterator operator++(int) {
				const_iterator Ans = *this;
				operator++();
				return Ans;
			}
			const_iterator& operator--() {
				if(Itr == BItr->begin()) {
					--BItr;
					Itr = BItr->end();
				}
				--Itr;
				return *this;
			}
			const_iterator operator--(int) {
				const_iterator Ans = *this;
				operator--();
				return Ans;
			}
			const_iterator& operator+=(difference_type n) {
				if(n<0)return operator-=(-n);

				if(n < std::distance(Itr, BItr->end())) {
					Itr += n;
				}else{
					auto BlockSize = BItr->size();
					n -= std::distance(Itr, BItr->end());
					++BItr;

					BItr += n/BlockSize;
					Itr = std::next(BItr->begin(), n%BlockSize);
				}
				return *this;
			}
			const_iterator& operator-=(difference_type n) {
				if(n<0)return operator+=(-n);

				if(n < std::distance(BItr->begin(), Itr)) {
					Itr -= n;
				} else {
					n -= std::distance(BItr->begin(), Itr);
					--BItr;
					auto BlockSize = BItr->size();

					BItr -= n/BlockSize;
					Itr = std::next(BItr->end()-1, -(n%BlockSize));
				}
				return *this;
			}
			friend const_iterator operator+(const const_iterator& v, difference_type n) {
				auto v2 = v;
				v2 += n;
				return v2;
			}
			friend const_iterator operator+(difference_type n, const const_iterator& v) {
				return v+n;
			}
			friend const_iterator operator-(const const_iterator& v, difference_type n) {
				auto v2 = v;
				v2 -= n;
				return v2;
			}
			friend difference_type operator-(const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr > v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v2.Bitr->size());
				else if(v1.BItr < v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v1.Bitr->size());
				else return v1.Itr - v2.Itr;
			}
			friend bool operator==(const const_iterator& v1, const const_iterator&  v2) {
				return v1.BItr == v2.BItr && v1.Itr == v2.Itr;
			}
			friend bool operator!=(const const_iterator&  v1, const const_iterator&  v2) {
				return v1.BItr != v2.BItr || v1.Itr != v2.Itr;
			}
			friend bool operator< (const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr < v2.Itr;
			}
			friend bool operator<=(const const_iterator& v1, const const_iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr <= v2.Itr;
			}
			friend bool operator> (const const_iterator& v1, const const_iterator&  v2) {
				return operator<(v2, v1);
			}
			friend bool operator>=(const const_iterator& v1, const const_iterator&  v2) {
				return operator<=(v2, v1);
			}
		public:
			point_type point()const { return BItr->point(Itr); }
			block_const_iterator block_itr() { return BItr; }
			element_const_iterator element_itr() { return Itr; }
		private:
			block_const_iterator BItr;
			element_const_iterator Itr;
		};
		struct iterator {
		public:
			using value_type = typename this_type::value_type;
			using difference_type = int;
			using reference = typename this_type::reference;
			using pointer = typename this_type::pointer;
			using iterator_category = std::random_access_iterator_tag;
		public:
			iterator() = default;
			iterator(block_iterator BItr_, element_iterator Itr_):BItr(BItr_),Itr(Itr_){}
			operator const_iterator() { return const_iterator(BItr, Itr); }
		public:
			reference operator*() {
				return Itr.operator*();
			}
			reference operator[](difference_type n) {
				return (*this + n).operator*();
			}
			pointer operator->() {
				return Itr.operator->();
			}
			iterator& operator++() {
				++Itr;
				if(Itr == BItr->end()) {
					++BItr;
					Itr = BItr->begin();
				}
				return *this;
			}
			iterator operator++(int) {
				iterator Ans = *this;
				operator++();
				return Ans;
			}
			iterator& operator--() {
				if(Itr == BItr->begin()) {
					--BItr;
					Itr = BItr->end();
				}
				--Itr;
				return *this;
			}
			iterator operator--(int) {
				iterator Ans = *this;
				operator--();
				return Ans;
			}
			iterator& operator+=(difference_type n) {
				if(n<0)return operator-=(-n);

				if(n < std::distance(Itr, BItr->end())) {
					Itr += n;
				} else {
					auto BlockSize = BItr->size();
					n -= std::distance(Itr, BItr->end());
					++BItr;

					BItr += n/BlockSize;
					Itr = std::next(BItr->begin(), n%BlockSize);
				}
				return *this;
			}
			iterator& operator-=(difference_type n) {
				if(n<0)return operator+=(-n);

				if(n < std::distance(BItr->begin(), Itr)) {
					Itr -= n;
				} else {
					n -= std::distance(BItr->begin(), Itr);
					--BItr;
					auto BlockSize = BItr->size();

					BItr -= n/BlockSize;
					Itr = std::next(BItr->end()-1, -(n%BlockSize));
				}
				return *this;
			}
			friend iterator operator+(const iterator& v, difference_type n) {
				auto v2 = v;
				v2 += n;
				return v2;
			}
			friend iterator operator+(difference_type n, const iterator& v) {
				return v+n;
			}
			friend iterator operator-(const iterator& v, difference_type n) {
				auto v2 = v;
				v2 -= n;
				return v2;
			}
			friend difference_type operator-(const iterator& v1, const iterator&  v2) {
				if(v1.BItr > v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v2.Bitr->size());
				else if(v1.BItr < v2.BItr)return std::distance(v1.BItr->begin(), v1.Itr) - std::distance(v2.BItr->begin(), v2.Itr) + (v1.BItr - v2.BItr)*(v1.Bitr->size());
				else return v1.Itr - v2.Itr;
			}
			friend bool operator==(const iterator& v1, const iterator& v2) {
				return v1.BItr == v2.BItr && v1.Itr == v2.Itr;
			}
			friend bool operator!=(const iterator& v1, const iterator& v2) {
				return v1.BItr != v2.BItr || v1.Itr != v2.Itr;
			}
			friend bool operator< (const iterator& v1, const iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr < v2.Itr;
			}
			friend bool operator<=(const iterator& v1, const iterator&  v2) {
				if(v1.BItr < v2.BItr) return true;
				else if(v1.BItr > v2.BItr) return false;
				else return v1.Itr <= v2.Itr;
			}
			friend bool operator> (const iterator& v1, const iterator&  v2) {
				return operator<(v2, v1);
			}
			friend bool operator>=(const iterator& v1, const iterator&  v2) {
				return operator<=(v2, v1);
			}
		public:
			point_type point()const { return BItr->point(Itr); }
			block_iterator block_itr() { return BItr; }
			element_iterator element_itr() { return Itr; }
		private:
			block_iterator BItr;
			element_iterator Itr;
		};
	public:
		block_lattice()noexcept:block_lattice(extent_type(10)) {}
		explicit block_lattice(extent_type BlockExtent)noexcept
			: Blocks()
			, Indexer(BlockExtent)
			, BlockNum(0)
			, HintPos(0){
			BlockSize = Indexer.lattice_size();
			Blocks.push_back(block(point_type(0), Indexer, BlockSize));
		}
		template<typename... others>
		explicit block_lattice(std::size_t Size_, others... Others_)noexcept: block_lattice(extent_type{ Size_,static_cast<std::size_t>(Others_)... }) {}
	public:
		bool empty()const{ return block_num()==0; }
		void clear() { BlockNum = 0; HintPos = 0; }
		std::size_t size()const { return block_num()*block_size(); }
		void block_resize(extent_type BlockExtent){
			if(empty()) {
				Indexer.resize(BlockExtent);
				BlockSize = Indexer.lattice_size();
			} else {
				this_type New(BlockExtent);
				auto End = end();
				for(auto Itr = begin(); Itr!=End; ++Itr) {
					New[Itr.point()] = *Itr;
				}
				*this = std::move(New);
			}
		}
		template<typename... others>
		void block_resize(std::size_t Size_, others... Others_) {
			block_resize(extent_type{ Size_,static_cast<std::size_t>(Others_)... });
		}
	public://manipulation related to block
		//!Get block extent
		extent_type block_extent()const { return Indexer.extent(); }
		//!Get block size
		size_type block_size()const { return BlockSize; }
		//!Get block number
		size_type block_num()const { return BlockNum; }
		//!Get block access iterator at begin
		block_iterator block_begin() { return Blocks.begin(); }
		//!Get block access iterator at begin
		block_const_iterator block_begin()const { return Blocks.begin(); }
		//!Get block access iterator at end
		block_iterator block_end() { return Blocks.begin()+BlockNum; }
		//!Get block access iterator at end
		block_const_iterator block_end()const { return Blocks.begin()+BlockNum; }
		//!Remove block
		void block_erase(block_iterator Itr) {
			if(Itr == block_end())return;
			if(std::distance(block_begin(), Itr)<=HintPos) {
				--HintPos;
			}
			std::rotate(Itr, Itr+1, block_end());
			--BlockNum;
		}
		//!Remove block
		template<typename block_condition_>
		void block_erase_if(block_condition_ BlockCondition){
			BlockNum = std::distance(
				block_begin(),
				hmLib::swap_remove_if(block_begin(), block_end(), std::forward<block_condition_>(BlockCondition))
			);
			HintPos = BlockNum;
		}
		template<typename element_condition_>
{'fraction_non_alphanumeric': 0.14446012228717328, 'fraction_numerical': 0.010045017805549956, 'mean_word_length': 3.643113398845734, 'pattern_counts': {'":': 0, '<': 111, '<?xml version=': 0, '>': 155, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5418436', 'n_tokens_mistral': 12247, 'n_tokens_neox': 10424, 'n_words': 2357}