<commit_before>###
    TODO: Add a @observe() and @observeChanges() just like
    Meteor's collection API. Good for List and AutoList.
###


class J.List
    constructor: (arr = [], equalsFunc = J.util.equals) ->
        unless @ instanceof J.List
            return new J.List arr, equalsFunc

        if arr instanceof J.List
            arr = arr.getValues()

        unless _.isArray arr
            throw new Meteor.Error "Not an array: #{arr}"

        @equalsFunc = equalsFunc

        fields = {}
        for x, i in arr
            fields[i] = x

        @readOnly = false

        @_dict = J.Dict fields

    _resize: (size) ->
        @_dict.replaceKeys ("#{i}" for i in [0...size])

    clear: ->
        @resize 0

    clone: ->
        # Nonreactive because a clone's fields are their
        # own new piece of application state
        @constructor Tracker.nonreactive => @getValues()

    contains: (value) ->
        # Reactive.
        # The current implementation invalidates somewhat
        # too much.
        # We could make the reactivity more efficient by
        # using a special hashSet of @_containsDeps
        # (one per value argument), but it would be
        # tricky to handle calls to @contains(v)
        # when v isn't J.Dict.encodeKey-able.
        value in @getValues()

    deepEquals: (x) ->
        # Reactive
        return false unless x instanceof @constructor
        J.util.deepEquals @toArr(), x.toArr()

    extend: (values) ->
        valuesArr =
            if values instanceof J.List
                values.getValues()
            else values

        adder = {}
        for value, i in valuesArr
            adder["#{@size() + i}"] = value
        @_dict.setOrAdd adder

    find: (f = _.identity) ->
        # Reactive
        for i in [0...@size()]
            x = @get i
            return x if f x

    filter: (f = _.identity) ->
        # Reactive
        J.List _.filter @getValues(), f

    forEach: (f) ->
        # Reactive
        # Like @map but:
        # - Not parallel
        # - Lets you return undefined
        # - Returns an array, not an AutoList
        f(v, i) for v, i in @getValues()

    get: (index) ->
        # Reactive
        unless _.isNumber(index)
            throw new Meteor.Error "Index must be a number"
        try
            @_dict.forceGet "#{index}"
        catch e
            throw e
            # TODO: look for missing-key and throw new Meteor.Error "List index out of range"

    getConcat: (lst) ->
        # Reactive
        if Tracker.active
            J.AutoList(
                => @size() + lst.size()
                (i) =>
                    if i < @size()
                        @get i
                    else
                        lst.get i - @size()
            )
        else
            J.List @getValues().concat lst.getValues()

    getReversed: ->
        # Reactive
        @map (value, i) => @get @size() - 1 - i

    getSorted: (keySpec = J.util.sortKeyFunc) ->
        # Reactive
        sortKeys = @map J.util._makeSortKeyFunc keySpec # Good to do this in parallel
        items = _.map @getValues(), (v, i) -> index: i, value: v
        J.List _.map(
            J.util.sortByKey items, (item) -> sortKeys[item.index]
            (item) -> item.value
        )

    getValues: ->
        # Reactive
        @_dict.get "#{i}" for i in [0...@size()]

    join: (separator) ->
        # Reactive
        @getValues().join separator

    indexOf: (x, equalsFunc = J.util.equals) ->
        for i in [0...@size()]
            y = @get i
            return i if equalsFunc y, x
        -1

    lazyMap: (f) ->
        # Reactive
        if Tracker.active
            J.AutoList(
                => @size()
                (i) => f @get(i), i
                null # This makes it lazy
            )
        else
            J.List @getValues().map f

    map: (f) ->
        # Reactive
        # Enables parallel fetching
        if Tracker.active
            J.AutoList(
                => @size()
                (i) => f @get(i), i
                true # This makes it not lazy
            )
        else
            J.List @getValues().map f

    push: (value) -><commit_msg>Parallelized join and filter<commit_after>###
    TODO: Add a @observe() and @observeChanges() just like
    Meteor's collection API. Good for List and AutoList.
###


class J.List
    constructor: (arr = [], equalsFunc = J.util.equals) ->
        unless @ instanceof J.List
            return new J.List arr, equalsFunc

        if arr instanceof J.List
            arr = arr.getValues()

        unless _.isArray arr
            throw new Meteor.Error "Not an array: #{arr}"

        @equalsFunc = equalsFunc

        fields = {}
        for x, i in arr
            fields[i] = x

        @readOnly = false

        @_dict = J.Dict fields

    _resize: (size) ->
        @_dict.replaceKeys ("#{i}" for i in [0...size])

    clear: ->
        @resize 0

    clone: ->
        # Nonreactive because a clone's fields are their
        # own new piece of application state
        @constructor Tracker.nonreactive => @getValues()

    contains: (value) ->
        # Reactive.
        # The current implementation invalidates somewhat
        # too much.
        # We could make the reactivity more efficient by
        # using a special hashSet of @_containsDeps
        # (one per value argument), but it would be
        # tricky to handle calls to @contains(v)
        # when v isn't J.Dict.encodeKey-able.
        value in @getValues()

    deepEquals: (x) ->
        # Reactive
        return false unless x instanceof @constructor
        J.util.deepEquals @toArr(), x.toArr()

    extend: (values) ->
        valuesArr =
            if values instanceof J.List
                values.getValues()
            else values

        adder = {}
        for value, i in valuesArr
            adder["#{@size() + i}"] = value
        @_dict.setOrAdd adder

    find: (f = _.identity) ->
        # Reactive
        for i in [0...@size()]
            x = @get i
            return x if f x

    filter: (f = _.identity) ->
        # Reactive
        J.List _.filter @map().getValues(), f

    forEach: (f) ->
        # Reactive
        # Like @map but:
        # - Not parallel
        # - Lets you return undefined
        # - Returns an array, not an AutoList
        f(v, i) for v, i in @getValues()

    get: (index) ->
        # Reactive
        unless _.isNumber(index)
            throw new Meteor.Error "Index must be a number"
        try
            @_dict.forceGet "#{index}"
        catch e
            throw e
            # TODO: look for missing-key and throw new Meteor.Error "List index out of range"

    getConcat: (lst) ->
        # Reactive
        if Tracker.active
            J.AutoList(
                => @size() + lst.size()
                (i) =>
                    if i < @size()
                        @get i
                    else
                        lst.get i - @size()
                true
            )
        else
            J.List @getValues().concat lst.getValues()

    getReversed: ->
        # Reactive
        @map (value, i) => @get @size() - 1 - i

    getSorted: (keySpec = J.util.sortKeyFunc) ->
        # Reactive
        sortKeys = @map J.util._makeSortKeyFunc keySpec # Good to do this in parallel
        items = _.map @getValues(), (v, i) -> index: i, value: v
        J.List _.map(
            J.util.sortByKey items, (item) -> sortKeys[item.index]
            (item) -> item.value
        )

    getValues: ->
        # Reactive
        @_dict.get "#{i}" for i in [0...@size()]

    join: (separator) ->
        # Reactive
        @map().getValues().join separator

    indexOf: (x, equalsFunc = J.util.equals) ->
        for i in [0...@size()]
            y = @get i
            return i if equalsFunc y, x
        -1

    lazyMap: (f = _.identity) ->
        # Reactive
        if Tracker.active
            J.AutoList(
                => @size()
                (i) => f @get(i), i
                null # This makes it lazy
            )
        else
            J.List @getValues().map f

    map: (f = _.identity) ->
        # Reactive
        # Enables parallel fetching
        if Tracker.active
            if f is _.identity and @ instanceof J.AutoList and @onChange
                @
            else
                J.AutoList(
                    => @size()
                    (i) => f @get(i), i
                    true # This makes it not lazy
                )
        else
            J.List @getValues().map f

    push: (value) ->
{'fraction_non_alphanumeric': 0.11114982578397213, 'fraction_numerical': 0.0016260162601626016, 'mean_word_length': 1.3482410689937279, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4755055', 'n_tokens_mistral': 2536, 'n_tokens_neox': 2426, 'n_words': 794}