% parallel.parfor.PoolOptions parforOptions for running on parallel.parfor.PoolEngine

% Copyright 2018-2021 The MathWorks, Inc.

classdef PoolOptions < parallel.parfor.Options
    properties (SetAccess = immutable)
        Pool          (1,1)
        MaxNumWorkers (1,1) double
    end
    
    properties (GetAccess = private, SetAccess = immutable)
        IsThreadPool (1,1) logical
    end
    
    methods
        function obj = PoolOptions(pool, maxNumWorkers, varargin)
            obj = obj@parallel.parfor.Options(varargin{:});
            assert(isa(pool, 'parallel.Pool'), ...
                'Expected a parallel.Pool.');
            obj.Pool = pool;
            % Resolve to the NumWorkers of the pool here.
            obj.MaxNumWorkers = min(obj.Pool.NumWorkers, maxNumWorkers);
            obj.IsThreadPool = isa(obj.Pool, 'parallel.internal.pool.NonClusterPoolMixin');
            if obj.IsThreadPool && maxNumWorkers < obj.Pool.NumWorkers
                error(message('MATLAB:parallel:parfor:ThreadsMaxNumWorkers', ...
                    class(obj.Pool)));
            end
        end
        
        function engine = createEngine(obj, initData, parforF)
            if obj.IsThreadPool
                engine = parallel.internal.parfor.ParfevalParforEngine(...
                    obj.RangePartitionMethod, obj.SubrangeSize, ...
                    obj.Pool, initData, parforF);
            else
                if isa(obj.Pool.hGetSession, "parallel.internal.pool.CppBackedSession")
                    engine = parallel.internal.parfor.ParforEngine(...
                        obj.RangePartitionMethod, obj.SubrangeSize, ...
                        obj.Pool, obj.MaxNumWorkers, initData, parforF);
                else
                    engine = distcomp.remoteparfor(...
                        obj.RangePartitionMethod, obj.SubrangeSize, ...
                        obj.Pool, obj.MaxNumWorkers, initData, parforF);
                end
            end
        end
    end
    
    
    methods (Access = protected)
        function group = getSpecificPropertyGroup(obj)
            group = struct('Pool', obj.Pool, ...
                'MaxNumWorkers', obj.MaxNumWorkers);
            group = matlab.mixin.util.PropertyGroup(group);
        end
    end
    
    methods (Static, Hidden)
        function poolOpts = build(pool, varargin)
            if nargin == 3 && ...
                    isequal(varargin{1}, 'MaxNumWorkers') && ...
                    iIsValidMaxNumWorkers(varargin{2})
                % Short-circuit for commonest case
                poolOpts = parallel.parfor.PoolOptions(pool, varargin{2});
            else
                p = parallel.parfor.Options.getBaseOptionsParser();
                p.addParameter('MaxNumWorkers', Inf, @iIsValidMaxNumWorkers);
                p.parse(varargin{:});
                poolOpts = parallel.parfor.PoolOptions(pool, p.Results.MaxNumWorkers, ...
                    p.Results, p.UsingDefaults);
            end
        end
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function ok = iIsValidMaxNumWorkers(M)
ok = isnumeric(M) && ...
    isscalar(M) && ...
    isreal(M) && ...
    (isinf(M) || (M > 0 && M == fix(M)));
if ~ok
    error(message('MATLAB:parallel:parfor:InvalidMaxNumWorkers'));
end
end
