diff --git a/src/dataType/utTermSize.erl b/src/dataType/utTermSize.erl new file mode 100644 index 0000000..c0e3d1a --- /dev/null +++ b/src/dataType/utTermSize.erl @@ -0,0 +1,99 @@ +-module(utTermSize). + +-export([ + byteSize/1 + , byteSize/2 +]). + +-define(HEAP_BINARY_LIMIT, 64). + +byteSize(Term) -> + byteSize(Term, erlang:system_info(wordsize)). + +byteSize(Term, WordSize) -> + byteSizeTermLocal(Term, WordSize) + byteSizeTerms(Term). + +byteSizeTerms(Term) when is_list(Term) -> + byteSizeTermsInList(Term, 0); +byteSizeTerms(Term) when is_tuple(Term) -> + if + Term == {} -> + 0; + true -> + byteSizeTermsInTuple(1, erlang:tuple_size(Term), Term, 0) + end; +byteSizeTerms(Term) when is_map(Term) -> + maps:fold( + fun(K, V, Bytes) -> + byteSizeTerms(K) + byteSizeTerms(V) + Bytes + end, 0, Term); +byteSizeTerms(Term) -> + byteSizeTerm(Term). + +byteSizeTermsInList([], SumSize) -> + SumSize; +byteSizeTermsInList([Term | L], SumSize) -> + TermSize = byteSizeTerms(Term), + byteSizeTermsInList(L, TermSize + SumSize); +byteSizeTermsInList(Term, SumSize) -> + % element of improper list + byteSizeTerms(Term) + SumSize. + +byteSizeTermsInTuple(Size, Size, Term, SumSize) -> + byteSizeTerms(erlang:element(Size, Term)) + SumSize; +byteSizeTermsInTuple(I, Size, Term, SumSize) -> + TermSize = byteSizeTerms(erlang:element(I, Term)), + byteSizeTermsInTuple(I + 1, Size, Term, TermSize + SumSize). + +byteSizeTerm(Term) -> + byteSizeTermGlobal(Term). + +byteSizeTermLocal(Term, WordSize) -> + % stack/register size + heap size + (1 + erts_debug:flat_size(Term)) * WordSize. + +byteSizeTermGlobal(Term) when is_binary(Term) -> + % global data storage within allocators + BinarySize = erlang:byte_size(Term), + if + BinarySize > ?HEAP_BINARY_LIMIT -> + % refc binary + BinarySize; + true -> + % heap binary + 0 + end; +byteSizeTermGlobal(_) -> + 0. + +-define(TEST, 64). +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +internal_test() -> + RefcBinary = <<1:((?HEAP_BINARY_LIMIT + 1) * 8)>>, + HeapBinary = <<1:(?HEAP_BINARY_LIMIT * 8)>>, + true = (7 == (1 + erts_debug:flat_size(RefcBinary))), + % doesn't work in console shell + % (process heap size of binary is excluded + % when executed in the console shell) + true = (11 == (1 + erts_debug:flat_size(HeapBinary))), + true = (4 == (1 + erts_debug:flat_size(<<1:8>>))), + + 24 = byteSize(<<>>, 8), + 32 = byteSize(<<"abc">>, 8), + 32 = byteSize(<<$a, $b, $c>>, 8), + 8 = byteSize([], 8), + 24 = byteSize([0|[]], 8), + 24 = byteSize([1|2], 8), % improper list + 16 = byteSize({}, 8), + 24 = byteSize({0}, 8), + 8 = byteSize(0, 8), + 8 = byteSize(erlang:self(), 8), + 8 = byteSize(atom, 8), + 88 = byteSize(#{1=>1, 2=>2, 3=>3}, 8), + 136 = byteSize(#{1=>RefcBinary, 2=>2, 3=>3}, 8) - erlang:byte_size(RefcBinary), + ok. + +-endif. +