<commit_before>% @copyright 2007-2014 Zuse Institute Berlin

%   Licensed under the Apache License, Version 2.0 (the "License");
%   you may not use this file except in compliance with the License.
%   You may obtain a copy of the License at
%
%       http://www.apache.org/licenses/LICENSE-2.0
%
%   Unless required by applicable law or agreed to in writing, software
%   distributed under the License is distributed on an "AS IS" BASIS,
%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%   See the License for the specific language governing permissions and
%   limitations under the License.

%% @author <NAME> <<EMAIL>>
%% @doc    Utility Functions.
%% @end
%% @version $Id$
-module(util).

-author('<EMAIL>').
-vsn('$Id$').

-include("scalaris.hrl").

-ifdef(with_export_type_support).
-export_type([time_utc/0]).
-endif.
-export([escape_quotes/1,
         min/2, max/2, log/2, log2/1, ceil/1, floor/1,
         logged_exec/1,
         randomelem/1, randomelem_and_length/1, pop_randomelem/1, pop_randomelem/2,
         get_stacktrace/0, get_linetrace/0, get_linetrace/1,
         do_throw/1,
         extract_from_list_may_not_exist/2,
         minus_all/2, minus_first/2,
         delete_if_exists/2,
         map_with_nr/3,
         par_map/2, par_map/3,
         lists_split/2, lists_keystore2/5,
         lists_partition3/2,
         lists_remove_at_indices/2,
         sublist/3, lists_index_of/2,
         lists_check_min_length/2,
         sleep_for_ever/0, shuffle/1, get_proc_in_vms/1,random_subset/2,
         gb_trees_largest_smaller_than/2, gb_trees_foldl/3, pow/2,
         zipfoldl/5, safe_split/2, '=:<'/2,
         split_unique/2, split_unique/3, split_unique/4,
         ssplit_unique/2, ssplit_unique/3, ssplit_unique/4,
         smerge2/2, smerge2/3, smerge2/4, smerge2/6,
         is_unittest/0, make_filename/1,
         app_get_env/2,
         app_check_running/1,
         timestamp2us/1, us2timestamp/1,
         time_plus_s/2, time_plus_ms/2, time_plus_us/2,
         readable_utc_time/1,
         for_to/3, for_to_ex/3, for_to_ex/4, for_to_fold/5,
         collect_while/1]).
-export([list_set_nth/3]).
-export([debug_info/0, debug_info/1]).
-export([print_bits/2, bin_xor/2]).
-export([if_verbose/1, if_verbose/2]).
-export([tc/3, tc/2, tc/1]).
-export([wait_for/1, wait_for/2,
         wait_for_process_to_die/1,
         wait_for_table_to_disappear/2,
         ets_tables_of/1]).
-export([round/2]).

-export([repeat/3, repeat/4, parallel_run/5]).

-export([empty/1]).

-export([extint2atom/1]).

% RRD helpers which don't belong to the rrd datastructure
-export([ rrd_combine_timing_slots/3
         , rrd_combine_timing_slots/4
         , rrd_combine_gauge_slots/3
         , rrd_combine_gauge_slots/4
         , rrd_combine_slots/6
    ]).

% feeder for tester
-export([readable_utc_time_feeder/1]).
-export([map_with_nr_feeder/3]).
-export([par_map_feeder/2, par_map_feeder/3]).
-export([lists_partition3_feeder/2]).

-export([sets_map/2]).

-type us_timestamp() :: non_neg_integer(). % micro seconds since Epoch

-type time_utc() :: {{1970..10000, 1..12, 1..31}, {0..23, 0..59, 0..59}}.

-type args() :: [term()].
-type accumulatorFun(T, U) :: fun((T, U) -> U).
-type repeat_params() :: parallel |
                         collect |
                         {accumulate, accumulatorFun(any(), R), R}. %{accumulate, fun, accumulator init value}

%% @doc Executes wait_for/2 with a WaitTime of 10ms.
-spec wait_for(fun(() -> boolean())) -> ok.
wait_for(F) -> wait_for(F, 10).

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses (send_local_after/2 and receive) or timer:sleep/1 to wait to
%%      return control flow to e.g. proto_sched depending on whether the caller
%%      is a gen_component or not.
-spec wait_for(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for(F, WaitTime) ->
    case gen_component:is_gen_component(self()) of
        true  -> wait_for2(F, WaitTime);
        false -> wait_for1(F, WaitTime)
    end.

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses send_local_after/2 and receive to wait to return control flow to
%%       e.g. proto_sched and is thus _NOT_ suitable for gen_components.
-spec wait_for1(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for1(F, WaitTime) ->
    case F() of
        true  -> ok;
        false ->
            comm:send_local_after(WaitTime, self(), {continue_wait}),
            trace_mpath:thread_yield(),
            receive
                ?SCALARIS_RECV({continue_wait},% ->
                               wait_for1(F, WaitTime))
            end
    end.

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses timer:sleep/1 to wait and is thus suitable for gen_components.
-spec wait_for2(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for2(F, WaitTime) ->
    case F() of
        true  -> ok;
        false -> timer:sleep(WaitTime),
                 wait_for2(F, WaitTime)
    end.

%% @doc Waits for the given process (name or pid) to die.
-spec wait_for_process_to_die(pid() | atom()) -> ok.
wait_for_process_to_die(Name) when is_atom(Name) ->
    wait_for(fun() ->
                     case erlang:whereis(Name) of
                         undefined -> true;
                         Pid       -> not is_process_alive(Pid)
                     end
             end);
wait_for_process_to_die(Pid) when is_pid(Pid) ->
    wait_for(fun() -> not is_process_alive(Pid) end).<commit_msg>util:wait_for1/2: make sure no former message interferes<commit_after>% @copyright 2007-2014 Zuse Institute Berlin

%   Licensed under the Apache License, Version 2.0 (the "License");
%   you may not use this file except in compliance with the License.
%   You may obtain a copy of the License at
%
%       http://www.apache.org/licenses/LICENSE-2.0
%
%   Unless required by applicable law or agreed to in writing, software
%   distributed under the License is distributed on an "AS IS" BASIS,
%   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%   See the License for the specific language governing permissions and
%   limitations under the License.

%% @author <NAME> <<EMAIL>>
%% @doc    Utility Functions.
%% @end
%% @version $Id$
-module(util).

-author('<EMAIL>').
-vsn('$Id$').

-include("scalaris.hrl").

-ifdef(with_export_type_support).
-export_type([time_utc/0]).
-endif.
-export([escape_quotes/1,
         min/2, max/2, log/2, log2/1, ceil/1, floor/1,
         logged_exec/1,
         randomelem/1, randomelem_and_length/1, pop_randomelem/1, pop_randomelem/2,
         get_stacktrace/0, get_linetrace/0, get_linetrace/1,
         do_throw/1,
         extract_from_list_may_not_exist/2,
         minus_all/2, minus_first/2,
         delete_if_exists/2,
         map_with_nr/3,
         par_map/2, par_map/3,
         lists_split/2, lists_keystore2/5,
         lists_partition3/2,
         lists_remove_at_indices/2,
         sublist/3, lists_index_of/2,
         lists_check_min_length/2,
         sleep_for_ever/0, shuffle/1, get_proc_in_vms/1,random_subset/2,
         gb_trees_largest_smaller_than/2, gb_trees_foldl/3, pow/2,
         zipfoldl/5, safe_split/2, '=:<'/2,
         split_unique/2, split_unique/3, split_unique/4,
         ssplit_unique/2, ssplit_unique/3, ssplit_unique/4,
         smerge2/2, smerge2/3, smerge2/4, smerge2/6,
         is_unittest/0, make_filename/1,
         app_get_env/2,
         app_check_running/1,
         timestamp2us/1, us2timestamp/1,
         time_plus_s/2, time_plus_ms/2, time_plus_us/2,
         readable_utc_time/1,
         for_to/3, for_to_ex/3, for_to_ex/4, for_to_fold/5,
         collect_while/1]).
-export([list_set_nth/3]).
-export([debug_info/0, debug_info/1]).
-export([print_bits/2, bin_xor/2]).
-export([if_verbose/1, if_verbose/2]).
-export([tc/3, tc/2, tc/1]).
-export([wait_for/1, wait_for/2,
         wait_for_process_to_die/1,
         wait_for_table_to_disappear/2,
         ets_tables_of/1]).
-export([round/2]).

-export([repeat/3, repeat/4, parallel_run/5]).

-export([empty/1]).

-export([extint2atom/1]).

% RRD helpers which don't belong to the rrd datastructure
-export([ rrd_combine_timing_slots/3
         , rrd_combine_timing_slots/4
         , rrd_combine_gauge_slots/3
         , rrd_combine_gauge_slots/4
         , rrd_combine_slots/6
    ]).

% feeder for tester
-export([readable_utc_time_feeder/1]).
-export([map_with_nr_feeder/3]).
-export([par_map_feeder/2, par_map_feeder/3]).
-export([lists_partition3_feeder/2]).

-export([sets_map/2]).

-type us_timestamp() :: non_neg_integer(). % micro seconds since Epoch

-type time_utc() :: {{1970..10000, 1..12, 1..31}, {0..23, 0..59, 0..59}}.

-type args() :: [term()].
-type accumulatorFun(T, U) :: fun((T, U) -> U).
-type repeat_params() :: parallel |
                         collect |
                         {accumulate, accumulatorFun(any(), R), R}. %{accumulate, fun, accumulator init value}

%% @doc Executes wait_for/2 with a WaitTime of 10ms.
-spec wait_for(fun(() -> boolean())) -> ok.
wait_for(F) -> wait_for(F, 10).

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses (send_local_after/2 and receive) or timer:sleep/1 to wait to
%%      return control flow to e.g. proto_sched depending on whether the caller
%%      is a gen_component or not.
-spec wait_for(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for(F, WaitTime) ->
    case gen_component:is_gen_component(self()) of
        true  -> wait_for2(F, WaitTime);
        false -> wait_for1(F, WaitTime)
    end.

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses send_local_after/2 and receive to wait to return control flow to
%%       e.g. proto_sched and is thus _NOT_ suitable for gen_components.
-spec wait_for1(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for1(F, WaitTime) ->
    case F() of
        true  -> ok;
        false ->
            WaitID = uid:get_pids_uid(),
            comm:send_local_after(WaitTime, self(), {continue_wait, WaitID}),
            trace_mpath:thread_yield(),
            receive
                ?SCALARIS_RECV({continue_wait, WaitID},% ->
                               wait_for1(F, WaitTime))
            end
    end.

%% @doc Waits for F/0 to become true and checks every WaitTime Milliseconds.
%%      Uses timer:sleep/1 to wait and is thus suitable for gen_components.
-spec wait_for2(fun(() -> boolean()), WaitTimeInMs::pos_integer()) -> ok.
wait_for2(F, WaitTime) ->
    case F() of
        true  -> ok;
        false -> timer:sleep(WaitTime),
                 wait_for2(F, WaitTime)
    end.

%% @doc Waits for the given process (name or pid) to die.
-spec wait_for_process_to_die(pid() | atom()) -> ok.
wait_for_process_to_die(Name) when is_atom(Name) ->
    wait_for(fun() ->
                     case erlang:whereis(Name) of
                         undefined -> true;
                         Pid       -> not is_process_alive(Pid)
                     end
             end);
wait_for_process_to_die(Pid) when is_pid(Pid) ->
    wait_for(fun() -> not is_process_alive(Pid) end).
{'fraction_non_alphanumeric': 0.13155555555555556, 'fraction_numerical': 0.02951111111111111, 'mean_word_length': 2.677999346191566, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1245939', 'n_tokens_mistral': 4037, 'n_tokens_neox': 3932, 'n_words': 899}