<commit_before>// Copyright 2014-08-30 PlanBase Inc. & <NAME>
//
// 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.

package org.organicdesign.fp.xform;

import org.organicdesign.fp.Or;
import org.organicdesign.fp.function.Function1;
import org.organicdesign.fp.function.Function2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 An immutable description of operations to be performed (a transformation, transform, or x-form).
 When foldLeft() is called, the Xform definition is "compiled" into a mutable transformation which
 is then carried out.  This allows certain performance shortcuts (such as doing a drop with index
 addition instead of iteration) and also hides the mutability otherwise inherent in a
 transformation.

 Xform is an abstract class.  Most of the methods on Xform produce immutable descriptions of actions
 to take at a later time.  These are represented by ___Desc classes.  When foldLeft() is called
 (or any of the helper methods that wrap it), that produces a result by first stringing together
 a bunch of Operations (____Op classes) and then "running" them.  This is analogous to compiling
 a program and running it.  The ____Desc classes are like the immutable source, the ____Op classes
 like the op-codes it's compiled into.

 Special thanks to <NAME> for pointing me toward separating the mutation from the
 description of a transformation.  Also to <NAME> (@extempore2) whose lectures provided
 an outline for what was ideal and also what was important.  All errors are my own.
 -Glen 2015-08-30
 */
public abstract class Xform<A> implements Transformable<A> {

    enum OpStrategy { HANDLE_INTERNALLY, ASK_SUPPLIER, CANNOT_HANDLE; }

    private static final Object TERMINATE = new Object();
    @SuppressWarnings("unchecked")
    private A terminate() { return (A) TERMINATE; }

    /**
     These are mutable operations that the transform carries out when it is run.  This is like the
     compiled "op codes" in contrast to the Xform is like the immutable "source code" of the
     transformation description.
     */
    static abstract class Operation {
        // Time using a linked list of ops instead of array, so that we can easily remove ops from
        // the list when they are used up.
        Function1<Object,Boolean> filter = null;
        Function1 map = null;
        Function1<Object,Iterable> flatMap = null;

        /**
         Drops as many items as the source can handle.
         @param num the number of items to drop
         @return  whether the source can handle the take, or pass-through (ask-supplier), or can't
         do either.
         */
        public Or<Long,OpStrategy> drop(long num) {
            return (num < 1) ? Or.good(0L)
                             : Or.bad(OpStrategy.CANNOT_HANDLE);
        }

        /**
         Takes as many items as the source can handle.
         @param num the number of items to take.
         @return whether the source can handle the take, or pass-through (ask-supplier), or can't
         do either.
         */
        public OpStrategy take(long num) { return OpStrategy.CANNOT_HANDLE; }

        /**
         We need to model this as a separate op for when the previous op is CANNOT_HANDLE.  It is
         coded as a filter, but still needs to be modeled separately so that subsequent drops can be
         combined into the earliest single explicit drop op.  Such combinations are additive,
         meaning that drop(3).drop(5) is equivalent to drop(8).
         */
        private static class DropOp extends Operation {
            private long leftToDrop;
            DropOp(long drop) {
                leftToDrop = drop;
                filter = o -> {
                    if (leftToDrop > 0) {
                        leftToDrop = leftToDrop - 1;
                        return Boolean.FALSE;
                    }
                    return Boolean.TRUE;
                };
            }
            @Override public Or<Long,OpStrategy> drop(long num) {
                leftToDrop = leftToDrop + num;
                return Or.good(num);
            }
        }

        private static class FilterOp extends Operation {
            FilterOp(Function1<Object,Boolean> func) { filter = func; }
        }

        private static class MapOp extends Operation {
            MapOp(Function1 func) { map = func; }
            @Override public Or<Long,OpStrategy> drop(long num) {
                return Or.bad(OpStrategy.ASK_SUPPLIER);
            }
            @Override public OpStrategy take(long num) { return OpStrategy.ASK_SUPPLIER; }
        }

        // TODO: FlatMap should drop and take internally using addition/subtraction on each output
        // TODO: list instead of testing each list item individually.
        private static class FlatMapOp extends Operation {
//            ListSourceDesc<U> cache = null;
//            int numToDrop = 0;

            FlatMapOp(Function1<Object,Iterable> func) { flatMap = func; }
        }

        /**
         We need to model this as a separate op for when the previous op is CANNOT_HANDLE.  It is
         coded as a map, but still needs to be modeled separately so that subsequent takes can be
         combined into the earliest single explicit take op.  Such combination is a pick-least of
         all the takes, meaning that take(5).take(3) is equivalent to take(3).
         */
        private static class TakeOp extends Operation {
            private long numToTake;
            TakeOp(long take) {
                numToTake = take;
                map = a -> {
                    if (numToTake > 0) {
                        numToTake = numToTake - 1;
                        return a;
                    }
                    return TERMINATE;
                };
            }

            @Override public OpStrategy take(long num) {
                if (num < 0) {
                    throw new IllegalArgumentException("Can't take less than 0 items.");
                }
                if (num < numToTake) {
                    numToTake = num;
                }
                return OpStrategy.HANDLE_INTERNALLY;
            }
        }
    } // end class Operation

    /**
     A RunList is a list of Operations "complied" from an Xform.  It contains an Iterable data
     source (or some day and array source or List source) and a List of Operation op-codes.

     A RunList is also a SourceProvider, since the output of one transform can be the input to
     another.  FlatMap is implemented that way.  Notice that there are almost no generic types used
     here: Since the input could be one type, and each map or flatmap operation could change that to
     another type.

     For speed, we ignore all that in the "compiled" version and just use Objects and avoid any
     wrapping or casting.
     */
    private static class RunList implements Iterable {<commit_msg>Fixed typo found by <NAME> - thank you John!<commit_after>// Copyright 2014-08-30 PlanBase Inc. & <NAME>
//
// 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.

package org.organicdesign.fp.xform;

import org.organicdesign.fp.Or;
import org.organicdesign.fp.function.Function1;
import org.organicdesign.fp.function.Function2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 An immutable description of operations to be performed (a transformation, transform, or x-form).
 When foldLeft() is called, the Xform definition is "compiled" into a mutable transformation which
 is then carried out.  This allows certain performance shortcuts (such as doing a drop with index
 addition instead of iteration) and also hides the mutability otherwise inherent in a
 transformation.

 Xform is an abstract class.  Most of the methods on Xform produce immutable descriptions of actions
 to take at a later time.  These are represented by ___Desc classes.  When foldLeft() is called
 (or any of the helper methods that wrap it), that produces a result by first stringing together
 a bunch of Operations (____Op classes) and then "running" them.  This is analogous to compiling
 a program and running it.  The ____Desc classes are like the immutable source, the ____Op classes
 like the op-codes it's compiled into.

 Special thanks to <NAME> for pointing me toward separating the mutation from the
 description of a transformation.  Also to <NAME> (@extempore2) whose lectures provided
 an outline for what was ideal and also what was important.  All errors are my own.
 -Glen 2015-08-30
 */
public abstract class Xform<A> implements Transformable<A> {

    enum OpStrategy { HANDLE_INTERNALLY, ASK_SUPPLIER, CANNOT_HANDLE; }

    private static final Object TERMINATE = new Object();
    @SuppressWarnings("unchecked")
    private A terminate() { return (A) TERMINATE; }

    /**
     These are mutable operations that the transform carries out when it is run.  This is like the
     compiled "op codes" in contrast to the Xform is like the immutable "source code" of the
     transformation description.
     */
    static abstract class Operation {
        // Time using a linked list of ops instead of array, so that we can easily remove ops from
        // the list when they are used up.
        Function1<Object,Boolean> filter = null;
        Function1 map = null;
        Function1<Object,Iterable> flatMap = null;

        /**
         Drops as many items as the source can handle.
         @param num the number of items to drop
         @return  whether the source can handle the take, or pass-through (ask-supplier), or can't
         do either.
         */
        public Or<Long,OpStrategy> drop(long num) {
            return (num < 1) ? Or.good(0L)
                             : Or.bad(OpStrategy.CANNOT_HANDLE);
        }

        /**
         Takes as many items as the source can handle.
         @param num the number of items to take.
         @return whether the source can handle the take, or pass-through (ask-supplier), or can't
         do either.
         */
        public OpStrategy take(long num) { return OpStrategy.CANNOT_HANDLE; }

        /**
         We need to model this as a separate op for when the previous op is CANNOT_HANDLE.  It is
         coded as a filter, but still needs to be modeled separately so that subsequent drops can be
         combined into the earliest single explicit drop op.  Such combinations are additive,
         meaning that drop(3).drop(5) is equivalent to drop(8).
         */
        private static class DropOp extends Operation {
            private long leftToDrop;
            DropOp(long drop) {
                leftToDrop = drop;
                filter = o -> {
                    if (leftToDrop > 0) {
                        leftToDrop = leftToDrop - 1;
                        return Boolean.FALSE;
                    }
                    return Boolean.TRUE;
                };
            }
            @Override public Or<Long,OpStrategy> drop(long num) {
                leftToDrop = leftToDrop + num;
                return Or.good(num);
            }
        }

        private static class FilterOp extends Operation {
            FilterOp(Function1<Object,Boolean> func) { filter = func; }
        }

        private static class MapOp extends Operation {
            MapOp(Function1 func) { map = func; }
            @Override public Or<Long,OpStrategy> drop(long num) {
                return Or.bad(OpStrategy.ASK_SUPPLIER);
            }
            @Override public OpStrategy take(long num) { return OpStrategy.ASK_SUPPLIER; }
        }

        // TODO: FlatMap should drop and take internally using addition/subtraction on each output
        // TODO: list instead of testing each list item individually.
        private static class FlatMapOp extends Operation {
//            ListSourceDesc<U> cache = null;
//            int numToDrop = 0;

            FlatMapOp(Function1<Object,Iterable> func) { flatMap = func; }
        }

        /**
         We need to model this as a separate op for when the previous op is CANNOT_HANDLE.  It is
         coded as a map, but still needs to be modeled separately so that subsequent takes can be
         combined into the earliest single explicit take op.  Such combination is a pick-least of
         all the takes, meaning that take(5).take(3) is equivalent to take(3).
         */
        private static class TakeOp extends Operation {
            private long numToTake;
            TakeOp(long take) {
                numToTake = take;
                map = a -> {
                    if (numToTake > 0) {
                        numToTake = numToTake - 1;
                        return a;
                    }
                    return TERMINATE;
                };
            }

            @Override public OpStrategy take(long num) {
                if (num < 0) {
                    throw new IllegalArgumentException("Can't take less than 0 items.");
                }
                if (num < numToTake) {
                    numToTake = num;
                }
                return OpStrategy.HANDLE_INTERNALLY;
            }
        }
    } // end class Operation

    /**
     A RunList is a list of Operations "compiled" from an Xform.  It contains an Iterable data
     source (or some day and array source or List source) and a List of Operation op-codes.

     A RunList is also a SourceProvider, since the output of one transform can be the input to
     another.  FlatMap is implemented that way.  Notice that there are almost no generic types used
     here: Since the input could be one type, and each map or flatmap operation could change that to
     another type.

     For speed, we ignore all that in the "compiled" version and just use Objects and avoid any
     wrapping or casting.
     */
    private static class RunList implements Iterable {
{'fraction_non_alphanumeric': 0.06423064029500503, 'fraction_numerical': 0.0059001005698960775, 'mean_word_length': 2.1375683634833824, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6608628', 'n_tokens_mistral': 3819, 'n_tokens_neox': 3629, 'n_words': 1691}