<commit_before>-module(etorrent_pieceset).
-include("types.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-export([new/1,
         from_binary/2,
         to_binary/1,
         from_list/2,
         to_list/1,
         is_member/2,
         insert/2,
         intersection/2,
         difference/2,
         size/1,
         min/1]).

-record(pieceset, {
    size :: pos_integer(),
    elements :: binary()}).

-opaque pieceset() :: #pieceset{}.
-export_type([pieceset/0]).

%% @doc
%% Create an empty set of piece indexes. The set of pieces
%% is limited to contain pieces indexes from 0 to Size-1.
%% @end
-spec new(pos_integer()) -> pieceset().
new(Size) ->
    PaddingLen = paddinglen(Size),
    Elements = <<0:Size, 0:PaddingLen>>,
    #pieceset{size=Size, elements=Elements}.

%% @doc
%% Create a piece set based on a bitfield. The bitfield is
%% expected to contain at most Size pieces. The piece set
%% returned by this function is limited to contain at most
%% Size pieces, as a set returned from new/1 is.
%% The bitfield is expected to not be padded with more than 7 bits.
%% @end
-spec from_binary(binary(), pos_integer()) -> pieceset().
from_binary(Bin, Size) when is_binary(Bin) ->
    PaddingLen = paddinglen(Size),
    <<_:Size, PaddingValue:PaddingLen>> = Bin,
    %% All bits used for padding must be set to 0
    case PaddingValue of
        0 -> ok;
        _ -> error(badarg)
    end,
    #pieceset{size=Size, elements=Bin}.

%% @doc
%% Convert a piece set to a bitfield, the bitfield will
%% be padded with at most 7 bits set to zero.
%% @end
-spec to_binary(pieceset()) -> binary().
to_binary(Pieceset) ->
    #pieceset{elements=Elements} = Pieceset,
    Elements.

%% @doc
%% Convert an ordered list of piece indexes to a piece set.
%% @end
-spec from_list(list(pos_integer()), pos_integer()) -> pieceset().
from_list(List, Size) ->
    Pieceset = new(Size),
    from_list_(List, Pieceset).

from_list_([], Pieceset) ->
    Pieceset;
from_list_([H|T], Pieceset) ->
    from_list_(T, insert(H, Pieceset)).


%% @doc
%% Convert a piece set to an ordered list of the piece indexes
%% that are members of this set.
%% @end
-spec to_list(pieceset()) -> list(pos_integer()).
to_list(Pieceset) ->
    #pieceset{elements=Elements} = Pieceset,
    to_list(Elements, 0).

to_list(<<1:1, Rest/bitstring>>, Index) ->
    [Index|to_list(Rest, Index + 1)];
to_list(<<0:1, Rest/bitstring>>, Index) ->
    to_list(Rest, Index + 1);
to_list(<<>>, _) ->
    [].

%% @doc
%% Returns true if the piece is a member of the piece set,
%% false if not. If the piece index is negative or is larger
%% than the size of this piece set, the function exits with badarg.
%% @end
-spec is_member(pos_integer(), pieceset()) -> boolean().
is_member(PieceIndex, _) when PieceIndex < 0 ->
    error(badarg);
is_member(PieceIndex, Pieceset) ->
    #pieceset{size=Size, elements=Elements} = Pieceset,
    case PieceIndex < Size of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(PieceIndex + 1),
            <<_:PieceIndex, Status:1, _:PaddingLen, _/binary>> = Elements,
            Status > 0
    end.

%% @doc
%% Insert a piece into the piece index. If the piece index is
%% negative or larger than the size of this piece set, this
%% function exists with the reason badarg.
%% @end
-spec insert(pos_integer(), pieceset()) -> pieceset().
insert(PieceIndex, _) when PieceIndex < 0 ->
    error(badarg);
insert(PieceIndex, Pieceset) ->
    #pieceset{size=Size, elements=Elements} = Pieceset,
    case PieceIndex < Size of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(PieceIndex + 1),
            <<Low:PieceIndex, _:1, Padding:PaddingLen, High/binary>> = Elements,
            Updated = <<Low:PieceIndex, 1:1, Padding:PaddingLen, High/binary>>,
            Pieceset#pieceset{elements=Updated}
    end.

%% @doc
%% Return a piece set where each member is a member of both sets.
%% If both sets are not of the same size this function exits with badarg.
%% @end
-spec intersection(pieceset(), pieceset()) -> pieceset().
intersection(Set0, Set1) ->
    #pieceset{size=Size0, elements=Elements0} = Set0,
    #pieceset{size=Size1, elements=Elements1} = Set1,
    case Size0 == Size1 of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(Size0),
            <<E0:Size0, 0:PaddingLen>> = Elements0,
            <<E1:Size0, 0:PaddingLen>> = Elements1,
            Shared = E0 band E1,<commit_msg>Add delete function to pieceset module<commit_after>-module(etorrent_pieceset).
-include("types.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.

-export([new/1,
         from_binary/2,
         to_binary/1,
         from_list/2,
         to_list/1,
         is_member/2,
         insert/2,
         delete/2,
         intersection/2,
         difference/2,
         size/1,
         min/1]).

-record(pieceset, {
    size :: pos_integer(),
    elements :: binary()}).

-opaque pieceset() :: #pieceset{}.
-export_type([pieceset/0]).

%% @doc
%% Create an empty set of piece indexes. The set of pieces
%% is limited to contain pieces indexes from 0 to Size-1.
%% @end
-spec new(pos_integer()) -> pieceset().
new(Size) ->
    PaddingLen = paddinglen(Size),
    Elements = <<0:Size, 0:PaddingLen>>,
    #pieceset{size=Size, elements=Elements}.

%% @doc
%% Create a piece set based on a bitfield. The bitfield is
%% expected to contain at most Size pieces. The piece set
%% returned by this function is limited to contain at most
%% Size pieces, as a set returned from new/1 is.
%% The bitfield is expected to not be padded with more than 7 bits.
%% @end
-spec from_binary(binary(), pos_integer()) -> pieceset().
from_binary(Bin, Size) when is_binary(Bin) ->
    PaddingLen = paddinglen(Size),
    <<_:Size, PaddingValue:PaddingLen>> = Bin,
    %% All bits used for padding must be set to 0
    case PaddingValue of
        0 -> ok;
        _ -> error(badarg)
    end,
    #pieceset{size=Size, elements=Bin}.

%% @doc
%% Convert a piece set to a bitfield, the bitfield will
%% be padded with at most 7 bits set to zero.
%% @end
-spec to_binary(pieceset()) -> binary().
to_binary(Pieceset) ->
    #pieceset{elements=Elements} = Pieceset,
    Elements.

%% @doc
%% Convert an ordered list of piece indexes to a piece set.
%% @end
-spec from_list(list(pos_integer()), pos_integer()) -> pieceset().
from_list(List, Size) ->
    Pieceset = new(Size),
    from_list_(List, Pieceset).

from_list_([], Pieceset) ->
    Pieceset;
from_list_([H|T], Pieceset) ->
    from_list_(T, insert(H, Pieceset)).


%% @doc
%% Convert a piece set to an ordered list of the piece indexes
%% that are members of this set.
%% @end
-spec to_list(pieceset()) -> list(pos_integer()).
to_list(Pieceset) ->
    #pieceset{elements=Elements} = Pieceset,
    to_list(Elements, 0).

to_list(<<1:1, Rest/bitstring>>, Index) ->
    [Index|to_list(Rest, Index + 1)];
to_list(<<0:1, Rest/bitstring>>, Index) ->
    to_list(Rest, Index + 1);
to_list(<<>>, _) ->
    [].

%% @doc
%% Returns true if the piece is a member of the piece set,
%% false if not. If the piece index is negative or is larger
%% than the size of this piece set, the function exits with badarg.
%% @end
-spec is_member(pos_integer(), pieceset()) -> boolean().
is_member(PieceIndex, _) when PieceIndex < 0 ->
    error(badarg);
is_member(PieceIndex, Pieceset) ->
    #pieceset{size=Size, elements=Elements} = Pieceset,
    case PieceIndex < Size of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(PieceIndex + 1),
            <<_:PieceIndex, Status:1, _:PaddingLen, _/binary>> = Elements,
            Status > 0
    end.

%% @doc
%% Insert a piece into the piece index. If the piece index is
%% negative or larger than the size of this piece set, this
%% function exists with the reason badarg.
%% @end
-spec insert(pos_integer(), pieceset()) -> pieceset().
insert(PieceIndex, _) when PieceIndex < 0 ->
    error(badarg);
insert(PieceIndex, Pieceset) ->
    #pieceset{size=Size, elements=Elements} = Pieceset,
    case PieceIndex < Size of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(PieceIndex + 1),
            <<Low:PieceIndex, _:1, Padding:PaddingLen, High/binary>> = Elements,
            Updated = <<Low:PieceIndex, 1:1, Padding:PaddingLen, High/binary>>,
            Pieceset#pieceset{elements=Updated}
    end.

%% @doc
%% Delete a piece from a pice set. If the index is negative
%% or larger than the size of the piece set, this function
%% exits with reason badarg.
%% @end
-spec delete(pos_integer(), pieceset()) -> pieceset().
delete(PieceIndex, _) when PieceIndex < 0 ->
    error(badarg);
delete(PieceIndex, Pieceset) ->
    #pieceset{size=Size, elements=Elements} = Pieceset,
    case PieceIndex < Size of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(PieceIndex + 1),
            <<Low:PieceIndex, _:1, Padding:PaddingLen, High/binary>> = Elements,
            Updated = <<Low:PieceIndex, 0:1, Padding:PaddingLen, High/binary>>,
            Pieceset#pieceset{elements=Updated}
    end.

%% @doc
%% Return a piece set where each member is a member of both sets.
%% If both sets are not of the same size this function exits with badarg.
%% @end
-spec intersection(pieceset(), pieceset()) -> pieceset().
intersection(Set0, Set1) ->
    #pieceset{size=Size0, elements=Elements0} = Set0,
    #pieceset{size=Size1, elements=Elements1} = Set1,
    case Size0 == Size1 of
        false ->
            error(badarg);
        true ->
            PaddingLen = paddinglen(Size0),
            <<E0:Size0, 0:PaddingLen>> = Elements0,
            <<E1:Size0, 0:PaddingLen>> = Elements1,
            Shared = E0 band E1,
{'fraction_non_alphanumeric': 0.1391057487579844, 'fraction_numerical': 0.012369461624252256, 'mean_word_length': 2.998378597486826, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 116, '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': '3615982', 'n_tokens_mistral': 3314, 'n_tokens_neox': 3173, 'n_words': 958}