struct IndexDefault end
Base.getindex(container::AbstractArray, ::IndexDefault) = zero(eltype(container))

struct UnitRangeExt <: AbstractRange{Integer}
	range::UnitRange
	stop
end
Base.length(iter::UnitRangeExt) = iter.stop - iter.range.start + 1
Base.iterate(iter::UnitRangeExt) = (iter.range.start, iter.range.start)
function Base.iterate(iter::UnitRangeExt, state::Integer)
	state == iter.stop && return nothing
	state += one(state)
	el = state > iter.range.stop ? IndexDefault() : state
	(el, state)
end

struct EachSequence <: AbstractRange{Integer}
	seqlen::Integer
	len::Integer
	rem::Bool
end
Base.length(iter::EachSequence) = cld(iter.len, iter.seqlen)
function Base.iterate(iter::EachSequence, state::Integer = 0)
	state >= iter.len && return nothing
	stop = state + iter.seqlen
	if !iter.rem || stop <= iter.len
		el = state+1:stop
	else
		el = UnitRangeExt(state+1:iter.len, stop)
	end
	(el, stop)
end
function eachsequence(seqlen::Integer, len::Integer; rem::Bool = false)
	EachSequence(seqlen, len, rem)
end

struct LongSteps <: AbstractRange{Integer}
	n::Integer
	unitl::Integer
	spacel::Integer
	offset::Integer
end
Base.length(iter::LongSteps) = iter.n*iter.unitl
function Base.iterate(iter::LongSteps, state::Tuple = (1, 1, iter.offset))
	nunit, nid, offset = state
	if nunit > iter.n
		return nothing
	end
	val = offset + nid
	if nid == iter.unitl
		nunit += 1
		nid = 1
		offset = offset + iter.unitl + iter.spacel
	else
		nid += 1
	end
	state = (nunit, nid, offset)
	return (val, state)
end

fromhexunit(x::UInt8) = x <= 0x39 ? x - 0x30 : x - 0x61 + 0xa
fromhexunit(x::Char) = fromhexunit(UInt8(x))
tohexunit(x::UInt8) = x < 0xa ? x + 0x30 : x + 0x61 - 0xa

frombase64unit(x::UInt8) = x >= 0x61 ? x - 0x61 + 0x1a :
	x >= 0x41 ? x - 0x41 :
	x >= 0x30 ? x - 0x30 + 0x34 :
	x == 0x2b ? 0x3e : 0x3f
frombase64unit(x::Char) = frombase64unit(UInt8(x))
tobase64unit(x::UInt8) = x <= 0x19 ? x + 0x41 :
	x <= 0x33 ? x + 0x61 - 0x1a :
	x <= 0x3d ? x + 0x30 - 0x34 :
	x == 0x3e ? 0x2b : 0x2f

function getint(arr::BitArray, itr, type::Type{T} where T <: Integer = UInt8)
	num = zero(type)
	for i in itr
		num <<= 1
		if arr[i]
			num += one(type)
		end
	end
	num
end
function setint!(arr::BitArray, itr, num::Integer)
	for i in reverse(itr)
		arr[i] = Bool(num&0x1)
		num >>= 1
	end
end

bitvector(str::AbstractString; mode = :hex) = _bitvector(Val(mode), str)::BitVector
function _bitvector(::Val{:ascii}, str::AbstractString)
	len = ncodeunits(str)
	bv = BitArray(undef, len*8)
	@inbounds for (i, range) in enumerate(eachsequence(8, len*8))
		setint!(bv, range, UInt8(str[i]))
	end
	bv
end
function _bitvector(::Val{:hex}, str::AbstractString)
	len = ncodeunits(str)
	bv = BitArray(undef, len*4)
	@inbounds for (i, range) in enumerate(eachsequence(4, len*4))
		setint!(bv, range, fromhexunit(str[i]))
	end
	bv
end
function _bitvector(::Val{:base64}, str::AbstractString)
	len = ncodeunits(str)
	len2 = len*6
	bv = BitArray(undef, len2)
	@inbounds for (i, range) in enumerate(eachsequence(6, len*6))
		setint!(bv, range, frombase64unit(str[i]))
	end
	for _ in 1:len2%8
		pop!(bv)
	end
	bv
end

Base.string(arr::BitVector; mode = :unicode) = _string(Val(mode), arr)::String
function _string(::Val{:unicode}, arr)
	es = eachsequence(8, length(arr); rem = true)
	sv = Base.StringVector(length(es))
	@inbounds for (i, range) in enumerate(es)
		sv[i] = getint(arr, range, UInt8)
	end
	String(sv)
end
_string(::Val{:bin}, arr) = bitstring(arr)
function _string(::Val{:hex}, arr)
	es = eachsequence(4, length(arr); rem = true)
	sv = Base.StringVector(length(es))
	@inbounds for (i, range) in enumerate(es)
		sv[i] = getint(arr, range, UInt8) |> tohexunit
	end
	String(sv)
end
function _string(::Val{:base64}, arr)
	es = eachsequence(6, length(arr); rem = true)
	orglen = length(es)
	extlen = iszero(orglen%4) ? 0 : 4-orglen%4
	sv = Base.StringVector(orglen + extlen)
	@inbounds for (i, range) in enumerate(es)
		sv[i] = getint(arr, range, UInt8) |> tobase64unit
	end
	for i in 1:extlen
		sv[i+orglen] = 0x3d
	end
	String(sv)
end