tags:

views:

494

answers:

2

What's best way to do the following? Binary -> list -> binary seems unnecessary.

binary_and(A, B) ->
    A2 = binary_to_list(A),
    B2 = binary_to_list(B),
    list_to_binary([U band V || {U, V} <- lists:zip(A2, B2)]).
+1  A: 

If don't care of performance, your code is absolutely OK. Otherwise you can do something different.

For example Erlang supports Integers of arbitrary size:

binary_and(A, B) ->
  Size = bit_size(A),
  <<X:Size>> = A,
  <<Y:Size>> = B,
  <<(X band Y):Size>>.

Or you can handcraft your own binary zip routine:

binary_and(A,B) -> binary_and(A, B, <<>>).

binary_and(<<A:8, RestA/bytes>>, <<B:8, RestB/bytes>>, Acc) ->
  binary_add(RestA, RestB, <<Acc/bytes, (A band B):8>>);
binary_and(<<>>, <<>>, Result) -> Result.

Or optimized version:

binary_and(A,B) -> binary_and(A, B, <<>>).

binary_and(<<A:64, RestA/bytes>>, <<B:64, RestB/bytes>>, Acc) ->
  binary_add(RestA, RestB, <<Acc/bytes, (A band B):64>>);
binary_and(<<A:32, RestA/bytes>>, <<B:32, RestB/bytes>>, Acc) ->
  binary_add(RestA, RestB, <<Acc/bytes, (A band B):32>>);
binary_and(<<A:16, RestA/bytes>>, <<B:16, RestB/bytes>>, Acc) ->
  binary_add(RestA, RestB, <<Acc/bytes, (A band B):16>>);
binary_and(<<A:8, RestA/bytes>>, <<B:8, RestB/bytes>>, Acc) ->
  binary_add(RestA, RestB, <<Acc/bytes, (A band B):8>>);
binary_and(<<>>, <<>>, Result) -> Result.

or more sophistic

binary_and(A,B) -> binary_and({A, B}, 0, <<>>).

binary_and(Bins, Index, Acc) ->
  case Bins of
    {<<_:Index/bytes, A:64, _/bytes>>, <<_:Index/bytes, B:64, _/bytes>>} ->
      binary_add(Bins, Index+8, <<Acc/bytes, (A band B):64>>);
    {<<_:Index/bytes, A:32, _/bytes>>, <<_:Index/bytes, B:32, _/bytes>>} ->
      binary_add(Bins, Index+4, <<Acc/bytes, (A band B):32>>);
    {<<_:Index/bytes, A:16, _/bytes>>, <<_:Index/bytes, B:16, _/bytes>>} ->
      binary_add(Bins, Index+2, <<Acc/bytes, (A band B):16>>);
    {<<_:Index/bytes, A:8, _/bytes>>, <<_:Index/bytes, B:8, _/bytes>>} ->
      binary_add(Bins, Index+1, <<Acc/bytes, (A band B):8>>);
    {<<_:Index/bytes>>, <<_:Index/bytes>>} -> Acc
  end.

Anyway you have to measure if you are really interested in performance. May be the first one is the fastest for your purposes.

Hynek -Pichi- Vychodil
+1  A: 

If you want to see the power of the dark side...

binary_and(A, B) ->
  Size = erlang:byte_size(A),
  Size = erlang:byte_size(B),
  Res = hipe_bifs:bytearray(Size, 0),
  binary_and(Res, A, B, 0, Size).

binary_and(Res, _A, _B, Size, Size) ->
  Res.

binary_and(Res, A, B, N, Size) ->
  Bin = hipe_bifs:bytearray_sub(A, N) band hipe_bifs:bytearray_sub(B,N),
  hipe_bifs:bytearray_update(Res, N, Bin),
  binary_and(Res, A, B, N+1, Size).
Zed