All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.graal.python.builtins.modules.ItertoolsModuleBuiltins Maven / Gradle / Ivy

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2017, 2023, Oracle and/or its affiliates.
 * Copyright (c) 2013, Regents of the University of California
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are
 * permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or other materials provided
 * with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.oracle.graal.python.builtins.modules;

import static com.oracle.graal.python.builtins.PythonBuiltinClassType.OverflowError;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
import static com.oracle.graal.python.nodes.ErrorMessages.ARG_CANNOT_BE_NEGATIVE;
import static com.oracle.graal.python.nodes.ErrorMessages.EXPECTED_INT_AS_R;
import static com.oracle.graal.python.nodes.ErrorMessages.ISLICE_WRONG_ARGS;
import static com.oracle.graal.python.nodes.ErrorMessages.MUST_BE_NON_NEGATIVE;
import static com.oracle.graal.python.nodes.ErrorMessages.NUMBER_IS_REQUIRED;
import static com.oracle.graal.python.nodes.ErrorMessages.STEP_FOR_ISLICE_MUST_BE;
import static com.oracle.graal.python.nodes.ErrorMessages.S_EXPECTED_GOT_P;
import static com.oracle.graal.python.nodes.ErrorMessages.S_FOR_ISLICE_MUST_BE;
import static com.oracle.graal.python.nodes.ErrorMessages.S_MUST_BE_S;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___COPY__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___FLOAT__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INDEX__;
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INT__;

import java.util.ArrayList;
import java.util.List;

import com.oracle.graal.python.annotations.ArgumentClinic;
import com.oracle.graal.python.builtins.Builtin;
import com.oracle.graal.python.builtins.CoreFunctions;
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
import com.oracle.graal.python.builtins.PythonBuiltins;
import com.oracle.graal.python.builtins.modules.BuiltinFunctions.IterNode;
import com.oracle.graal.python.builtins.objects.PNone;
import com.oracle.graal.python.builtins.objects.function.PKeyword;
import com.oracle.graal.python.builtins.objects.iterator.IteratorNodes.ToArrayNode;
import com.oracle.graal.python.builtins.objects.itertools.PAccumulate;
import com.oracle.graal.python.builtins.objects.itertools.PChain;
import com.oracle.graal.python.builtins.objects.itertools.PCombinations;
import com.oracle.graal.python.builtins.objects.itertools.PCombinationsWithReplacement;
import com.oracle.graal.python.builtins.objects.itertools.PCompress;
import com.oracle.graal.python.builtins.objects.itertools.PCount;
import com.oracle.graal.python.builtins.objects.itertools.PCycle;
import com.oracle.graal.python.builtins.objects.itertools.PDropwhile;
import com.oracle.graal.python.builtins.objects.itertools.PFilterfalse;
import com.oracle.graal.python.builtins.objects.itertools.PGroupBy;
import com.oracle.graal.python.builtins.objects.itertools.PGrouper;
import com.oracle.graal.python.builtins.objects.itertools.PIslice;
import com.oracle.graal.python.builtins.objects.itertools.PPairwise;
import com.oracle.graal.python.builtins.objects.itertools.PPermutations;
import com.oracle.graal.python.builtins.objects.itertools.PProduct;
import com.oracle.graal.python.builtins.objects.itertools.PRepeat;
import com.oracle.graal.python.builtins.objects.itertools.PStarmap;
import com.oracle.graal.python.builtins.objects.itertools.PTakewhile;
import com.oracle.graal.python.builtins.objects.itertools.PTeeDataObject;
import com.oracle.graal.python.builtins.objects.itertools.PZipLongest;
import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode;
import com.oracle.graal.python.lib.PyCallableCheckNode;
import com.oracle.graal.python.lib.PyLongAsIntNode;
import com.oracle.graal.python.lib.PyNumberAsSizeNode;
import com.oracle.graal.python.lib.PyObjectGetIter;
import com.oracle.graal.python.lib.PyObjectLookupAttr;
import com.oracle.graal.python.lib.PyObjectTypeCheck;
import com.oracle.graal.python.nodes.ErrorMessages;
import com.oracle.graal.python.nodes.PGuards;
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryClinicBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryClinicBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
import com.oracle.graal.python.nodes.util.CannotCastException;
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
import com.oracle.graal.python.runtime.exception.PException;
import com.oracle.graal.python.util.PythonUtils;
import com.oracle.truffle.api.dsl.Bind;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Cached.Exclusive;
import com.oracle.truffle.api.dsl.Cached.Shared;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
import com.oracle.truffle.api.dsl.NodeFactory;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.LoopNode;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.InlinedBranchProfile;
import com.oracle.truffle.api.profiles.InlinedConditionProfile;
import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile;
import com.oracle.truffle.api.profiles.LoopConditionProfile;

@CoreFunctions(defineModule = "itertools")
public final class ItertoolsModuleBuiltins extends PythonBuiltins {

    @Override
    protected List> getNodeFactories() {
        return ItertoolsModuleBuiltinsFactory.getFactories();
    }

    @Builtin(name = "accumulate", minNumOfPositionalArgs = 2, varArgsMarker = true, parameterNames = {"cls", "iterable", "func"}, keywordOnlyNames = {
                    "initial"}, constructsClass = PythonBuiltinClassType.PAccumulate, doc = "accumulate(iterable) --> accumulate object\n\nReturn series of accumulated sums.")
    @GenerateNodeFactory
    public abstract static class AccumulateNode extends PythonBuiltinNode {

        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        protected PAccumulate construct(VirtualFrame frame, Object cls, Object iterable, @SuppressWarnings("unused") PNone func, @SuppressWarnings("unused") PNone initial,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return create(frame, inliningTarget, cls, iterable, null, null, getIter);
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(initial)"})
        protected PAccumulate construct(VirtualFrame frame, Object cls, Object iterable, @SuppressWarnings("unused") PNone func, Object initial,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return create(frame, inliningTarget, cls, iterable, null, initial, getIter);
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(func)"})
        protected PAccumulate construct(VirtualFrame frame, Object cls, Object iterable, Object func, @SuppressWarnings("unused") PNone initial,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return create(frame, inliningTarget, cls, iterable, func, null, getIter);
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(func)", "!isNone(initial)"})
        protected PAccumulate construct(VirtualFrame frame, Object cls, Object iterable, Object func, Object initial,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return create(frame, inliningTarget, cls, iterable, func, initial, getIter);
        }

        private PAccumulate create(VirtualFrame frame, Node inliningTarget, Object cls, Object iterable, Object func, Object initial, PyObjectGetIter getIter) {
            PAccumulate self = factory().createAccumulate(cls);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            self.setFunc(func instanceof PNone ? null : func);
            self.setTotal(null);
            self.setInitial(initial instanceof PNone ? null : initial);
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        @SuppressWarnings("unused")
        protected Object notype(Object cls, Object iterable, Object func, Object initial,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "combinations", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PCombinations, parameterNames = {"cls", "iterable",
                    "r"}, doc = "combinations(iterable, r) --> combinations object\n\n" +
                                    "Return successive r-length combinations of elements in the iterable.\n\n" +
                                    "combinations(range(4), 3) --> (0,1,2), (0,1,3), (0,2,3), (1,2,3)")
    @ArgumentClinic(name = "r", conversion = ArgumentClinic.ClinicConversion.Int)
    @GenerateNodeFactory
    public abstract static class CombinationsNode extends PythonTernaryClinicBuiltinNode {

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.CombinationsNodeClinicProviderGen.INSTANCE;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "r >= 0"})
        Object construct(VirtualFrame frame, Object cls, Object iterable, int r,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode,
                        @Cached ToArrayNode toArrayNode,
                        @Cached LoopConditionProfile indicesLoopProfile) {
            PCombinations self = factory().createCombinations(cls);
            self.setPool(toArrayNode.execute(frame, iterable));

            int[] indices = new int[r];
            indicesLoopProfile.profileCounted(r);
            for (int i = 0; indicesLoopProfile.inject(i < r); i++) {
                indices[i] = i;
            }
            self.setIndices(indices);
            self.setR(r);
            self.setLastResult(null);
            self.setStopped(r > self.getPool().length);

            return self;
        }

        @SuppressWarnings("unused")
        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "r < 0"})
        Object construct(Object cls, Object iterable, int r,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(ValueError, MUST_BE_NON_NEGATIVE, "r");
        }

        @SuppressWarnings("unused")
        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        protected Object notype(Object cls, Object iterable, Object r,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "combinations_with_replacement", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PCombinationsWithReplacement, parameterNames = {"cls", "iterable",
                    "r"}, doc = "combinations_with_replacement(iterable, r) --> combinations_with_replacement object\n\n" +
                                    "Return successive r-length combinations of elements in the iterable\n" +
                                    "allowing individual elements to have successive repeats.\n" +
                                    "    combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC")
    @ArgumentClinic(name = "r", conversion = ArgumentClinic.ClinicConversion.Int)
    @GenerateNodeFactory
    public abstract static class CombinationsWithReplacementNode extends PythonTernaryClinicBuiltinNode {

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.CombinationsWithReplacementNodeClinicProviderGen.INSTANCE;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "r >= 0"})
        Object construct(VirtualFrame frame, Object cls, Object iterable, int r,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode,
                        @Cached ToArrayNode toArrayNode) {
            PCombinationsWithReplacement self = factory().createCombinationsWithReplacement(cls);
            self.setPool(toArrayNode.execute(frame, iterable));
            self.setR(r);

            self.setIndices(new int[r]);
            self.setLastResult(null);
            self.setStopped(self.getPool().length == 0 && r > 0);

            return self;
        }

        @SuppressWarnings("unused")
        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "r < 0"})
        Object construct(Object cls, Object iterable, int r,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(ValueError, MUST_BE_NON_NEGATIVE, "r");
        }

        @SuppressWarnings("unused")
        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        protected Object notype(Object cls, Object iterable, Object r,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "compress", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PCompress, parameterNames = {"cls", "data",
                    "selectors"}, doc = "Make an iterator that filters elements from *data* returning\n" +
                                    "only those that have a corresponding element in *selectors* that evaluates to\n" +
                                    "``True``.  Stops when either the *data* or *selectors* iterables has been\n" +
                                    "exhausted.\n" +
                                    "Equivalent to::\n\n" +
                                    "\tdef compress(data, selectors):\n" +
                                    "\t\t# compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F\n" +
                                    "\t\treturn (d for d, s in zip(data, selectors) if s)")
    @GenerateNodeFactory
    public abstract static class CompressNode extends PythonTernaryBuiltinNode {
        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PCompress construct(VirtualFrame frame, Object cls, Object data, Object selectors,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Exclusive @Cached IsTypeNode isTypeNode) {
            PCompress self = factory().createCompress(cls);
            self.setData(getIter.execute(frame, inliningTarget, data));
            self.setSelectors(getIter.execute(frame, inliningTarget, selectors));
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        @SuppressWarnings({"unused", "truffle-static-method"})
        protected Object notype(Object cls, Object[] arguments, PKeyword[] keywords,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "cycle", minNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PCycle, doc = "Make an iterator returning elements from the iterable and\n" +
                    "    saving a copy of each. When the iterable is exhausted, return\n" +
                    "    elements from the saved copy. Repeats indefinitely.\n\n" +
                    "    Equivalent to :\n\n" +
                    "    def cycle(iterable):\n" +
                    "    \tsaved = []\n" +
                    "    \tfor element in iterable:\n" +
                    "    \t\tyield element\n" +
                    "    \t\tsaved.append(element)\n" +
                    "    \twhile saved:\n" +
                    "    \t\tfor element in saved:\n" +
                    "    \t\t\tyield element")
    @GenerateNodeFactory
    public abstract static class CycleNode extends PythonBinaryBuiltinNode {

        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PCycle construct(VirtualFrame frame, Object cls, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Exclusive @Cached IsTypeNode isTypeNode) {
            PCycle self = factory().createCycle(cls);
            self.setSaved(new ArrayList<>());
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            self.setIndex(0);
            self.setFirstpass(false);
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        @SuppressWarnings({"unused", "truffle-static-method"})
        protected Object notype(Object cls, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "dropwhile", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PDropwhile, doc = "dropwhile(predicate, iterable) --> dropwhile object\n\n" +
                    "Drop items from the iterable while predicate(item) is true.\n" +
                    "Afterwards, return every element until the iterable is exhausted.")
    @GenerateNodeFactory
    public abstract static class DropwhileNode extends PythonTernaryBuiltinNode {
        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PDropwhile construct(VirtualFrame frame, Object cls, Object predicate, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Exclusive @Cached IsTypeNode isTypeNode) {
            PDropwhile self = factory().createDropwhile(cls);
            self.setPredicate(predicate);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            self.setDoneDropping(false);
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        @SuppressWarnings({"unused", "truffle-static-method"})
        protected Object notype(Object cls, Object predicate, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "filterfalse", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PFilterfalse, doc = "filterfalse(function or None, sequence) --> filterfalse object\n\n" +
                    "Return those items of sequence for which function(item) is false.\n" +
                    "If function is None, return the items that are false.")
    @GenerateNodeFactory
    public abstract static class FilterFalseNode extends PythonTernaryBuiltinNode {
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        protected PFilterfalse constructNoFunc(VirtualFrame frame, Object cls, @SuppressWarnings("unused") PNone func, Object sequence,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return construct(frame, cls, null, sequence, inliningTarget, getIter, isTypeNode);
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(func)", "!isNoValue(func)"})
        protected PFilterfalse construct(VirtualFrame frame, Object cls, Object func, Object sequence,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PFilterfalse self = factory().createFilterfalse(cls);
            self.setFunc(func);
            self.setSequence(getIter.execute(frame, inliningTarget, sequence));
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        @SuppressWarnings("unused")
        protected Object notype(Object cls, Object[] arguments, PKeyword[] keywords,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "groupby", minNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PGroupBy, parameterNames = {"cls", "iterable",
                    "key"}, doc = "Make an iterator that returns consecutive keys and groups from the\n" +
                                    "iterable. The key is a function computing a key value for each\n" +
                                    "element. If not specified or is None, key defaults to an identity\n" +
                                    "function and returns the element unchanged. Generally, the\n" +
                                    "iterable needs to already be sorted on the same key function.\n\n" +
                                    "The returned group is itself an iterator that shares the\n" +
                                    "underlying iterable with groupby(). Because the source is shared,\n" +
                                    "when the groupby object is advanced, the previous group is no\n" +
                                    "longer visible. So, if that data is needed later, it should be\n" +
                                    "stored as a list:\n\n" +
                                    "\tgroups = []\n" +
                                    "\tuniquekeys = []\n" +
                                    "\tfor k, g in groupby(data, keyfunc):\n" +
                                    "\t\tgroups.append(list(g))      # Store group iterator as a list\n" +
                                    "\t\tuniquekeys.append(k)")
    @ArgumentClinic(name = "key", defaultValue = "PNone.NONE")
    @GenerateNodeFactory
    public abstract static class GroupByNode extends PythonTernaryClinicBuiltinNode {

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.GroupByNodeClinicProviderGen.INSTANCE;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "isNone(key)"})
        protected PGroupBy constructNoType(VirtualFrame frame, Object cls, Object iterable, @SuppressWarnings("unused") PNone key,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return construct(frame, cls, iterable, null, inliningTarget, getIter, isTypeNode);
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(key)"})
        protected PGroupBy construct(VirtualFrame frame, Object cls, Object iterable, Object key,
                        @Bind("this") Node inliningTarget,
                        @Shared("getIter") @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PGroupBy self = factory().createGroupBy(cls);
            self.setKeyFunc(key);
            self.setIt(getIter.execute(frame, inliningTarget, iterable));
            return self;
        }

        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        @SuppressWarnings("unused")
        protected Object notype(Object cls, Object iterable, @SuppressWarnings("unused") PNone key,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "_grouper", minNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PGrouper, parameterNames = {"$self", "parent", "tgtkey"})
    @GenerateNodeFactory
    public abstract static class GrouperNode extends PythonTernaryBuiltinNode {
        @SuppressWarnings("unused")
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        protected PGrouper construct(Object cls, PGroupBy parent, Object tgtKey,
                        @Bind("this") Node inliningTarget,
                        @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            return factory().createGrouper(parent, tgtKey);
        }

        @SuppressWarnings("unused")
        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isGroupBy(parent)"})
        Object construct(Object cls, Object parent, Object tgtky,
                        @Bind("this") Node inliningTarget,
                        @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.INCORRECT_USAGE_OF_INTERNAL_GROUPER);
        }

        protected boolean isGroupBy(Object obj) {
            return obj instanceof PGroupBy;
        }

        @SuppressWarnings("unused")
        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        protected Object notype(Object cls, PGroupBy parent, Object tgtKey,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "takewhile", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PTakewhile, doc = "Make an iterator that returns elements from the iterable as\n" +
                    "long as the predicate is true.\n\nEquivalent to :\n\ndef takewhile(predicate, iterable):\n\tfor x in iterable:\n\t\tif predicate(x):\n\t\t\tyield x\n" +
                    "\t\telse:\n\t\t\tbreak")
    @GenerateNodeFactory
    public abstract static class TakewhileNode extends PythonTernaryBuiltinNode {
        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PTakewhile construct(VirtualFrame frame, Object cls, Object predicate, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Exclusive @Cached IsTypeNode isTypeNode) {
            PTakewhile self = factory().createTakewhile(cls);
            self.setPredicate(predicate);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            return self;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        @SuppressWarnings({"unused", "truffle-static-method"})
        protected Object notype(Object cls, Object predicate, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "tee", minNumOfPositionalArgs = 1, parameterNames = {"iterable", "n"})
    @ArgumentClinic(name = "n", conversion = ArgumentClinic.ClinicConversion.Int, defaultValue = "2")
    @GenerateNodeFactory
    public abstract static class TeeNode extends PythonBinaryClinicBuiltinNode {
        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.TeeNodeClinicProviderGen.INSTANCE;
        }

        @SuppressWarnings("unused")
        @Specialization(guards = "n < 0")
        protected Object negativeN(Object iterable, int n) {
            throw raise(ValueError, S_MUST_BE_S, "n", ">=0");
        }

        @SuppressWarnings("unused")
        @Specialization(guards = "n == 0")
        protected Object zeroN(Object iterable, int n) {
            return factory().createTuple(PythonUtils.EMPTY_OBJECT_ARRAY);
        }

        @Specialization(guards = "n > 0")
        @SuppressWarnings("truffle-static-method")
        protected Object tee(VirtualFrame frame, Object iterable, int n,
                        @Bind("this") Node inliningTarget,
                        @Cached IterNode iterNode,
                        @Cached PyObjectLookupAttr getAttrNode,
                        @Cached PyCallableCheckNode callableCheckNode,
                        @Cached CallVarargsMethodNode callNode,
                        @Cached InlinedBranchProfile notCallableProfile) {
            Object it = iterNode.execute(frame, iterable, PNone.NO_VALUE);
            Object copyCallable = getAttrNode.execute(frame, inliningTarget, it, T___COPY__);
            if (!callableCheckNode.execute(inliningTarget, copyCallable)) {
                notCallableProfile.enter(inliningTarget);
                // as in Tee.__NEW__()
                PTeeDataObject dataObj = factory().createTeeDataObject(it);
                it = factory().createTee(dataObj, 0);
            }

            // return tuple([it] + [it.__copy__() for i in range(1, n)])
            Object[] tupleObjs = new Object[n];
            tupleObjs[0] = it;

            copyCallable = getAttrNode.execute(frame, inliningTarget, it, T___COPY__);
            for (int i = 1; i < n; i++) {
                tupleObjs[i] = callNode.execute(frame, copyCallable, PythonUtils.EMPTY_OBJECT_ARRAY, PKeyword.EMPTY_KEYWORDS);
            }
            return factory().createTuple(tupleObjs);
        }

    }

    @Builtin(name = "_tee_dataobject", minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true, constructsClass = PythonBuiltinClassType.PTeeDataObject)
    @GenerateNodeFactory
    public abstract static class TeeDataObjectNode extends PythonVarargsBuiltinNode {
        @SuppressWarnings("unused")
        @Specialization
        protected PTeeDataObject construct(Object cls, Object[] arguments, PKeyword[] keywords,
                        @Bind("this") Node inliningTarget,
                        @Cached IsTypeNode isTypeNode,
                        @Cached InlinedBranchProfile errorProfile) {
            if (!isTypeNode.execute(inliningTarget, cls)) {
                errorProfile.enter(inliningTarget);
                throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
            }
            return factory().createTeeDataObject();
        }
    }

    @Builtin(name = "permutations", minNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PPermutations, parameterNames = {"cls", "iterable",
                    "r"}, doc = "permutations(iterable[, r]) --> permutations object\n\n" +
                                    "Return successive r-length permutations of elements in the iterable.\n\n" + "permutations(range(3), 2) --> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)")
    @ArgumentClinic(name = "r", defaultValue = "PNone.NONE")
    @GenerateNodeFactory
    public abstract static class PermutationsNode extends PythonTernaryClinicBuiltinNode {
        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.PermutationsNodeClinicProviderGen.INSTANCE;
        }

        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        @SuppressWarnings("truffle-static-method")
        Object construct(VirtualFrame frame, Object cls, Object iterable, Object rArg,
                        @Bind("this") Node inliningTarget,
                        @Cached InlinedConditionProfile rIsNoneProfile,
                        @Cached ToArrayNode toArrayNode,
                        @Cached CastToJavaIntExactNode castToInt,
                        @Cached InlinedBranchProfile wrongRprofile,
                        @Cached InlinedBranchProfile negRprofile,
                        @Cached InlinedConditionProfile nrProfile,
                        @Cached InlinedLoopConditionProfile indicesLoopProfile,
                        @Cached InlinedLoopConditionProfile cyclesLoopProfile,
                        @SuppressWarnings("unused") @Cached IsTypeNode isTypeNode) {
            int r;
            Object[] pool = toArrayNode.execute(frame, iterable);
            if (rIsNoneProfile.profile(inliningTarget, PGuards.isNone(rArg))) {
                r = pool.length;
            } else {
                try {
                    r = castToInt.execute(inliningTarget, rArg);
                } catch (CannotCastException e) {
                    wrongRprofile.enter(inliningTarget);
                    throw raise(TypeError, EXPECTED_INT_AS_R);
                }
                if (r < 0) {
                    negRprofile.enter(inliningTarget);
                    throw raise(ValueError, MUST_BE_NON_NEGATIVE, "r");
                }
            }
            PPermutations self = factory().createPermutations(cls);
            self.setPool(pool);
            self.setR(r);
            int n = pool.length;
            self.setN(n);
            int nMinusR = n - r;
            if (nrProfile.profile(inliningTarget, nMinusR < 0)) {
                self.setStopped(true);
                self.setRaisedStopIteration(true);
            } else {
                self.setStopped(false);
                int[] indices = new int[n];
                indicesLoopProfile.profileCounted(inliningTarget, indices.length);
                LoopNode.reportLoopCount(inliningTarget, indices.length);
                for (int i = 0; indicesLoopProfile.inject(inliningTarget, i < indices.length); i++) {
                    indices[i] = i;
                }
                self.setIndices(indices);
                int[] cycles = new int[r];
                int idx = 0;
                cyclesLoopProfile.profileCounted(inliningTarget, r);
                LoopNode.reportLoopCount(inliningTarget, r);
                for (int i = n; cyclesLoopProfile.inject(inliningTarget, i > nMinusR); i--) {
                    cycles[idx++] = i;
                }
                self.setCycles(cycles);
                self.setRaisedStopIteration(false);
                self.setStarted(false);
                return self;
            }
            return self;
        }

        @Fallback
        @SuppressWarnings("unused")
        protected Object construct(Object cls, Object iterable, Object rArg) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "product", minNumOfPositionalArgs = 1, takesVarArgs = true, constructsClass = PythonBuiltinClassType.PProduct, keywordOnlyNames = {
                    "repeat"}, doc = "Cartesian product of input iterables.\n\n" +
                                    "Equivalent to nested for-loops in a generator expression. For example,\n ``product(A, B)`` returns the same as ``((x,y) for x in A for y in B)``.\n\n" +
                                    "The nested loops cycle like an odometer with the rightmost element advancing\n on every iteration.  This pattern creates a lexicographic ordering so that if\n" +
                                    " the input's iterables are sorted, the product tuples are emitted in sorted\n order.\n\nTo compute the product of an iterable with itself, specify the number of\n" +
                                    " repetitions with the optional *repeat* keyword argument.  For example,\n ``product(A, repeat=4)`` means the same as ``product(A, A, A, A)``.\n\n" +
                                    "This function is equivalent to the following code, except that the\n actual implementation does not build up intermediate results in memory::\n\n" +
                                    "def product(*args, **kwds):\n\t# product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy\n\t# product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111\n" +
                                    "\tpools = map(tuple, args) * kwds.get('repeat', 1)\n\tresult = [[]]\n\tfor pool in pools:\n\t\tresult = [x+[y] for x in result for y in pool]\n" +
                                    "\tfor prod in result:\n\t\tyield tuple(prod)")
    @GenerateNodeFactory
    public abstract static class ProductNode extends PythonBuiltinNode {

        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        Object constructNoneRepeat(VirtualFrame frame, Object cls, Object[] iterables, @SuppressWarnings("unused") PNone repeat,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @Shared @Cached ToArrayNode toArrayNode,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PProduct self = factory().createProduct(cls);
            constructOneRepeat(frame, self, iterables, toArrayNode);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "repeat == 1"}, limit = "1")
        @SuppressWarnings("truffle-static-method")
        Object constructOneRepeat(VirtualFrame frame, Object cls, Object[] iterables, @SuppressWarnings("unused") int repeat,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @Shared @Cached ToArrayNode toArrayNode,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            PProduct self = factory().createProduct(cls);
            constructOneRepeat(frame, self, iterables, toArrayNode);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "repeat > 1"}, limit = "1")
        @SuppressWarnings("truffle-static-method")
        Object construct(VirtualFrame frame, Object cls, Object[] iterables, int repeat,
                        @Bind("this") Node inliningTarget,
                        @Shared @Cached ToArrayNode toArrayNode,
                        @Cached InlinedLoopConditionProfile loopProfile,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            Object[][] lists = unpackIterables(frame, iterables, toArrayNode);
            Object[][] gears = new Object[lists.length * repeat][];
            loopProfile.profileCounted(inliningTarget, repeat);
            LoopNode.reportLoopCount(inliningTarget, repeat);
            for (int i = 0; loopProfile.inject(inliningTarget, i < repeat); i++) {
                PythonUtils.arraycopy(lists, 0, gears, i * lists.length, lists.length);
            }
            PProduct self = factory().createProduct(cls);
            construct(self, gears);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "repeat == 0"}, limit = "1")
        @SuppressWarnings("truffle-static-method")
        Object constructNoRepeat(Object cls, @SuppressWarnings("unused") Object[] iterables, @SuppressWarnings("unused") int repeat,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            PProduct self = factory().createProduct(cls);
            self.setGears(new Object[0][]);
            self.setIndices(new int[0]);
            self.setLst(null);
            self.setStopped(false);
            return self;
        }

        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "repeat < 0"}, limit = "1")
        Object constructNeg(Object cls, Object[] iterables, int repeat,
                        @Bind("this") Node inliningTarget,
                        @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ARG_CANNOT_BE_NEGATIVE, "repeat");
        }

        private static void constructOneRepeat(VirtualFrame frame, PProduct self, Object[] iterables, ToArrayNode toArrayNode) {
            Object[][] gears = unpackIterables(frame, iterables, toArrayNode);
            construct(self, gears);
        }

        private static void construct(PProduct self, Object[][] gears) {
            self.setGears(gears);
            for (int i = 0; i < gears.length; i++) {
                if (gears[i].length == 0) {
                    self.setIndices(null);
                    self.setLst(null);
                    self.setStopped(true);
                    return;
                }
            }
            self.setIndices(new int[gears.length]);
            self.setLst(null);
            self.setStopped(false);
        }

        private static Object[][] unpackIterables(VirtualFrame frame, Object[] iterables, ToArrayNode toArrayNode) {
            Object[][] lists = new Object[iterables.length][];
            for (int i = 0; i < lists.length; i++) {
                lists[i] = toArrayNode.execute(frame, iterables[i]);
            }
            return lists;
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        @SuppressWarnings("unused")
        protected Object construct(Object cls, Object iterables, Object repeat,
                        @Bind("this") Node inliningTarget,
                        @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "repeat", minNumOfPositionalArgs = 2, parameterNames = {"$self", "object",
                    "times"}, constructsClass = PythonBuiltinClassType.PRepeat, doc = "repeat(object [,times]) -> create an iterator which returns the object\n" +
                                    "for the specified number of times.  If not specified, returns the object\nendlessly.")
    @ArgumentClinic(name = "times", defaultValue = "PNone.NONE", useDefaultForNone = true)
    @GenerateNodeFactory
    public abstract static class RepeatNode extends PythonTernaryClinicBuiltinNode {

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.RepeatNodeClinicProviderGen.INSTANCE;
        }

        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)")
        Object constructNone(Object cls, Object object, @SuppressWarnings("unused") PNone times,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PRepeat self = factory().createRepeat(cls);
            self.setElement(object);
            self.setCnt(-1);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "times < 0"})
        Object constructNeg(Object cls, Object object, @SuppressWarnings("unused") int times,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PRepeat self = factory().createRepeat(cls);
            self.setElement(object);
            self.setCnt(0);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "times >= 0"})
        Object construct(Object cls, Object object, int times,
                        @SuppressWarnings("unused") @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            PRepeat self = factory().createRepeat(cls);
            self.setElement(object);
            self.setCnt(times);
            return self;
        }

        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "times >= 0"}, limit = "1")
        @SuppressWarnings("truffle-static-method")
        Object construct(VirtualFrame frame, Object cls, Object object, long times,
                        @Bind("this") Node inliningTarget,
                        @Cached PyLongAsIntNode asIntNode,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            PRepeat self = factory().createRepeat(cls);
            self.setElement(object);
            self.setCnt(asIntNode.execute(frame, inliningTarget, times));
            return self;
        }

        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = {"isTypeNode.execute(inliningTarget, cls)", "!isNone(times)", "!isInt(times)", "!isLong(times)"})
        Object construct(Object cls, Object object, Object times,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, S_EXPECTED_GOT_P, "integer", times);
        }

        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)")
        @SuppressWarnings("unused")
        protected Object notype(Object cls, Object object, Object times,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Shared("typeNode") @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }

    }

    @Builtin(name = "chain", minNumOfPositionalArgs = 1, takesVarArgs = true, constructsClass = PythonBuiltinClassType.PChain, doc = "Return a chain object whose .__next__() method returns elements from the\n" +
                    "first iterable until it is exhausted, then elements from the next\niterable, until all of the iterables are exhausted.")
    @GenerateNodeFactory
    public abstract static class ChainNode extends PythonBuiltinNode {
        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PChain construct(VirtualFrame frame, Object cls, Object[] iterables,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            PChain self = factory().createChain(cls);
            self.setSource(getIter.execute(frame, inliningTarget, factory().createList(iterables)));
            self.setActive(PNone.NONE);
            return self;
        }

        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected Object notype(Object cls, Object[] iterables,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "count", minNumOfPositionalArgs = 1, constructsClass = PythonBuiltinClassType.PCount, parameterNames = {"cls", "start", "step"})
    @ArgumentClinic(name = "start", defaultValue = "0", useDefaultForNone = true)
    @ArgumentClinic(name = "step", defaultValue = "1", useDefaultForNone = true)
    @GenerateNodeFactory
    public abstract static class CountNode extends PythonTernaryClinicBuiltinNode {

        @Override
        protected ArgumentClinicProvider getArgumentClinic() {
            return ItertoolsModuleBuiltinsClinicProviders.CountNodeClinicProviderGen.INSTANCE;
        }

        @Specialization
        @SuppressWarnings("truffle-static-method")
        Object construct(VirtualFrame frame, Object cls, Object start, Object step,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectTypeCheck typeCheckNode,
                        @Cached PyObjectLookupAttr lookupAttrNode,
                        @Cached InlinedBranchProfile startNumberProfile,
                        @Cached InlinedBranchProfile stepNumberProfile,
                        @Cached IsTypeNode isTypeNode) {
            if (!isTypeNode.execute(inliningTarget, cls)) {
                throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
            }
            PCount self = factory().createCount(cls);
            checkType(frame, inliningTarget, start, typeCheckNode, lookupAttrNode, startNumberProfile);
            checkType(frame, inliningTarget, step, typeCheckNode, lookupAttrNode, stepNumberProfile);
            self.setCnt(start);
            self.setStep(step);
            return self;
        }

        private void checkType(VirtualFrame frame, Node inliningTarget, Object obj, PyObjectTypeCheck typeCheckNode, PyObjectLookupAttr lookupAttrNode, InlinedBranchProfile isNumberProfile) {
            if (typeCheckNode.execute(inliningTarget, obj, PythonBuiltinClassType.PComplex) ||
                            lookupAttrNode.execute(frame, inliningTarget, obj, T___INDEX__) != PNone.NO_VALUE ||
                            lookupAttrNode.execute(frame, inliningTarget, obj, T___FLOAT__) != PNone.NO_VALUE ||
                            lookupAttrNode.execute(frame, inliningTarget, obj, T___INT__) != PNone.NO_VALUE) {
                isNumberProfile.enter(inliningTarget);
                return;
            }
            throw raise(TypeError, NUMBER_IS_REQUIRED);
        }
    }

    @Builtin(name = "starmap", minNumOfPositionalArgs = 3, constructsClass = PythonBuiltinClassType.PStarmap, doc = "starmap(function, sequence) --> starmap object\n\n" +
                    "Return an iterator whose values are returned from the function evaluated\n" +
                    "with an argument tuple taken from the given sequence.")
    @GenerateNodeFactory
    public abstract static class StarmapNode extends PythonTernaryBuiltinNode {
        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected PStarmap construct(VirtualFrame frame, Object cls, Object fun, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            PStarmap self = factory().createStarmap(cls);
            self.setFun(fun);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            return self;
        }

        @SuppressWarnings({"unused", "truffle-static-method"})
        @Specialization(guards = "!isTypeNode.execute(inliningTarget, cls)", limit = "1")
        protected Object construct(Object cls, Object fun, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @SuppressWarnings("unused") @Exclusive @Cached IsTypeNode isTypeNode) {
            throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
        }
    }

    @Builtin(name = "islice", minNumOfPositionalArgs = 2, takesVarArgs = true, constructsClass = PythonBuiltinClassType.PIslice)
    @GenerateNodeFactory
    public abstract static class IsliceNode extends PythonBuiltinNode {
        @Specialization
        @SuppressWarnings("truffle-static-method")
        Object constructOne(VirtualFrame frame, Object cls, Object iterable, Object[] args,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Cached PyNumberAsSizeNode asIntNode,
                        @Cached InlinedBranchProfile hasStart,
                        @Cached InlinedBranchProfile hasStop,
                        @Cached InlinedBranchProfile hasStep,
                        @Cached InlinedBranchProfile stopNotInt,
                        @Cached InlinedBranchProfile startNotInt,
                        @Cached InlinedBranchProfile stopWrongValue,
                        @Cached InlinedBranchProfile stepWrongValue,
                        @Cached InlinedBranchProfile wrongValue,
                        @Cached InlinedBranchProfile overflowBranch,
                        @Cached InlinedConditionProfile argsLen1,
                        @Cached InlinedConditionProfile argsLen2,
                        @Cached InlinedConditionProfile argsLen3,
                        @Cached InlinedBranchProfile wrongTypeBranch,
                        @Cached InlinedBranchProfile wrongArgsBranch,
                        @Cached IsTypeNode isTypeNode) {
            if (!isTypeNode.execute(inliningTarget, cls)) {
                wrongTypeBranch.enter(inliningTarget);
                throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
            }
            if (args.length == 0 || args.length > 3) {
                wrongArgsBranch.enter(inliningTarget);
                throw raise(TypeError, ISLICE_WRONG_ARGS);
            }
            int start = 0;
            int step = 1;
            int stop = -1;
            if (argsLen1.profile(inliningTarget, args.length == 1)) {
                if (args[0] != PNone.NONE) {
                    hasStop.enter(inliningTarget);
                    try {
                        stop = asIntNode.executeExact(frame, inliningTarget, args[0], OverflowError);
                    } catch (PException e) {
                        stopNotInt.enter(inliningTarget);
                        throw raise(ValueError, S_FOR_ISLICE_MUST_BE, "Indices");
                    }
                }
                if (stop < -1 || stop > SysModuleBuiltins.MAXSIZE) {
                    stopWrongValue.enter(inliningTarget);
                    throw raise(ValueError, S_FOR_ISLICE_MUST_BE, "Indices");
                }
            } else if (argsLen2.profile(inliningTarget, args.length == 2) || argsLen3.profile(inliningTarget, args.length == 3)) {
                if (args[0] != PNone.NONE) {
                    hasStart.enter(inliningTarget);
                    try {
                        start = asIntNode.executeExact(frame, inliningTarget, args[0], OverflowError);
                    } catch (PException e) {
                        startNotInt.enter(inliningTarget);
                        throw raise(ValueError, S_FOR_ISLICE_MUST_BE, "Indices");
                    }
                }
                if (args[1] != PNone.NONE) {
                    hasStop.enter(inliningTarget);
                    try {
                        stop = asIntNode.executeExact(frame, inliningTarget, args[1], OverflowError);
                    } catch (PException e) {
                        stopNotInt.enter(inliningTarget);
                        throw raise(ValueError, S_FOR_ISLICE_MUST_BE, "Stop argument");
                    }
                }
                if (start < 0 || stop < -1 || start > SysModuleBuiltins.MAXSIZE || stop > SysModuleBuiltins.MAXSIZE) {
                    wrongValue.enter(inliningTarget);
                    throw raise(ValueError, S_FOR_ISLICE_MUST_BE, "Indices");
                }
            }
            if (argsLen3.profile(inliningTarget, args.length == 3)) {
                if (args[2] != PNone.NONE) {
                    hasStep.enter(inliningTarget);
                    try {
                        step = asIntNode.executeExact(frame, inliningTarget, args[2], OverflowError);
                    } catch (PException e) {
                        overflowBranch.enter(inliningTarget);
                        step = -1;
                    }
                }
                if (step < 1) {
                    stepWrongValue.enter(inliningTarget);
                    throw raise(ValueError, STEP_FOR_ISLICE_MUST_BE);
                }
            }
            PIslice self = factory().createIslice(cls);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            self.setNext(start);
            self.setStop(stop);
            self.setStep(step);
            self.setCnt(0);
            return self;
        }
    }

    @Builtin(name = "zip_longest", minNumOfPositionalArgs = 1, takesVarArgs = true, constructsClass = PythonBuiltinClassType.PZipLongest, keywordOnlyNames = {
                    "fillvalue"}, doc = "zip_longest(iter1 [,iter2 [...]], [fillvalue=None]) --> zip_longest object\n\n" +
                                    "Return a zip_longest object whose .next() method returns a tuple where\n" +
                                    "the i-th element comes from the i-th iterable argument.  The .next()\n" +
                                    "method continues until the longest iterable in the argument sequence\n" +
                                    "is exhausted and then it raises StopIteration.  When the shorter iterables\n" +
                                    "are exhausted, the fillvalue is substituted in their place.  The fillvalue\n" +
                                    "defaults to None or can be specified by a keyword argument.")
    @GenerateNodeFactory
    public abstract static class ZipLongestNode extends PythonBuiltinNode {
        @Specialization
        Object construct(VirtualFrame frame, Object cls, Object[] args, Object fillValueIn,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIterNode,
                        @Cached InlinedConditionProfile fillIsNone,
                        @Cached InlinedLoopConditionProfile loopProfile,
                        @Cached IsTypeNode isTypeNode,
                        @Cached InlinedBranchProfile errorProfile) {
            if (!isTypeNode.execute(inliningTarget, cls)) {
                // Note: @Fallback or other @Specialization generate data-class
                errorProfile.enter(inliningTarget);
                throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
            }

            Object fillValue = fillValueIn;
            if (fillIsNone.profile(inliningTarget, PGuards.isPNone(fillValue))) {
                fillValue = null;
            }

            PZipLongest self = factory().createZipLongest(cls);
            self.setFillValue(fillValue);
            self.setNumActive(args.length);

            Object[] itTuple = new Object[args.length];
            loopProfile.profileCounted(inliningTarget, itTuple.length);
            LoopNode.reportLoopCount(inliningTarget, itTuple.length);
            for (int i = 0; loopProfile.inject(inliningTarget, i < itTuple.length); i++) {
                itTuple[i] = getIterNode.execute(frame, inliningTarget, args[i]);
            }
            self.setItTuple(itTuple);
            return self;
        }
    }

    @Builtin(name = "pairwise", minNumOfPositionalArgs = 2, constructsClass = PythonBuiltinClassType.PPairwise, doc = "Return an iterator of overlapping pairs taken from the input iterator.\n\n" +
                    "    s -> (s0,s1), (s1,s2), (s2, s3), ...")
    @GenerateNodeFactory
    public abstract static class PairwaiseNode extends PythonBinaryBuiltinNode {
        @Specialization
        protected PPairwise construct(VirtualFrame frame, Object cls, Object iterable,
                        @Bind("this") Node inliningTarget,
                        @Cached PyObjectGetIter getIter,
                        @Cached IsTypeNode isTypeNode,
                        @Cached InlinedBranchProfile errorProfile) {
            if (!isTypeNode.execute(inliningTarget, cls)) {
                // Note: @Fallback or other @Specialization generate data-class
                errorProfile.enter(inliningTarget);
                throw raise(TypeError, ErrorMessages.IS_NOT_TYPE_OBJ, "'cls'", cls);
            }

            PPairwise self = factory().createPairwise(cls);
            self.setIterable(getIter.execute(frame, inliningTarget, iterable));
            return self;
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy