// Copyright (C) 2013  Davis E. King (davis@dlib.net)
// License: Boost Software License   See LICENSE.txt for the full license.
#undef DLIB_PARALLEL_FoR_ABSTRACT_H__
#ifdef DLIB_PARALLEL_FoR_ABSTRACT_H__ 

#include "thread_pool_extension_abstract.h"

namespace dlib
{

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This is a convenience function for submitting a block of jobs to a
              thread_pool.  In particular, given the range [begin, end), this function will
              split the range into approximately tp.num_threads_in_pool()*chunks_per_thread
              blocks, which it will then submit to the thread_pool.  The given thread_pool
              will then call (obj.*funct)() on each of the subranges.
            - To be precise, suppose we have broken the range [begin, end) into the
              following subranges:
                - [begin[0], end[0])
                - [begin[1], end[1])
                - [begin[2], end[2])
                  ...
                - [begin[n], end[n])
              Then parallel_for_blocked() submits each of these subranges to tp for
              processing such that (obj.*funct)(begin[i], end[i]) is invoked for all valid
              values of i.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long, long),
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for_blocked(tp, begin, end, obj, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 4
    );
    /*!
        requires
            - chunks_per_thread > 0
            - begin <= end
        ensures
            - This is a convenience function for submitting a block of jobs to a
              thread_pool.  In particular, given the range [begin, end), this function will
              split the range into approximately tp.num_threads_in_pool()*chunks_per_thread
              blocks, which it will then submit to the thread_pool.  The given thread_pool
              will then call funct() on each of the subranges.
            - To be precise, suppose we have broken the range [begin, end) into the
              following subranges:
                - [begin[0], end[0])
                - [begin[1], end[1])
                - [begin[2], end[2])
                  ...
                - [begin[n], end[n])
              Then parallel_for_blocked() submits each of these subranges to tp for
              processing such that funct(begin[i], end[i]) is invoked for all valid values
              of i.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for_blocked (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for_blocked(tp, begin, end, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following function call:
              parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub) 
                {
                  for (long i = begin_sub; i < end_sub; ++i)
                      (obj.*funct)(i);  
                }, chunks_per_thread);
            - Therefore, this routine invokes (obj.*funct)(i) for all i in the range
              [begin, end).  However, it does so using tp.num_threads_in_pool() parallel
              threads.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        T& obj,
        void (T::*funct)(long),
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for(tp, begin, end, obj, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        thread_pool& tp,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following function call:
              parallel_for_blocked(tp, begin, end, [&](long begin_sub, long end_sub) 
                {
                  for (long i = begin_sub; i < end_sub; ++i)
                      funct(i);  
                }, chunks_per_thread);
            - Therefore, this routine invokes funct(i) for all i in the range [begin, end).
              However, it does so using tp.num_threads_in_pool() parallel threads.
            - This function will not perform any memory allocations or create any system
              resources such as mutex objects.
    !*/

// ----------------------------------------------------------------------------------------

    template <typename T>
    void parallel_for (
        unsigned long num_threads,
        long begin,
        long end,
        const T& funct,
        long chunks_per_thread = 4
    );
    /*!
        requires
            - begin <= end
            - chunks_per_thread > 0
        ensures
            - This function is equivalent to the following block of code:
                thread_pool tp(num_threads);
                parallel_for(tp, begin, end, funct, chunks_per_thread);
    !*/

// ----------------------------------------------------------------------------------------

}

#endif // DLIB_PARALLEL_FoR_ABSTRACT_H__


