PreviousUpNext

15.4.1199  src/lib/std/src/rw-vector-slice.pkg

## rw-vector-slice.pkg
## Author: Matthias Blume (blume@tti-c.org)

# Compiled by:
#     src/lib/std/src/standard-core.sublib


###           "Mathematics, rightly viewed, possesses not only truth,
###            but supreme beauty - a beauty cold and austere, like
###            that of sculpture, without appeal to any part of our
###            weaker nature, without the gorgeous trappings of painting
###            or music, yet sublimely pure, and capable of a stern
###            perfection such as only the greatest art can show."
###
###                                   -- Bertrand Russell.


stipulate
    package rwv =  rw_vector;                                   # rw_vector             is from   src/lib/std/src/rw-vector.pkg
herein

    package   rw_vector_slice
    : (weak)  Rw_Vector_Slice                                   # Rw_Vector_Slice       is from   src/lib/std/src/rw-vector-slice.api
    {
                                                                    # inline_t          is from   src/lib/core/init/built-in.pkg

        Slice(X) =  SLICE { base:       rwv::Rw_Vector(X),
                            start:      Int,
                            stop:       Int
                          };

        # Fast add/subtract avoiding
        # the overflow test:
        #
        infix my --- +++ ;
        #
        fun x --- y = inline_t::tu::copyt_tagged_int (inline_t::tu::copyf_tagged_int x - inline_t::tu::copyf_tagged_int y);
        fun x +++ y = inline_t::tu::copyt_tagged_int (inline_t::tu::copyf_tagged_int x + inline_t::tu::copyf_tagged_int y);

        unsafe_get = inline_t::poly_rw_vector::get;
        unsafe_set = inline_t::poly_rw_vector::set;

        ro_unsafe_get = inline_t::poly_vector::get;

        rw_length = inline_t::poly_rw_vector::length;
        ro_length = inline_t::poly_vector::length;

        fun length (SLICE { start, stop, ... } )
            =
            stop --- start;

        fun get (SLICE { base, start, stop }, i)
            =
            {   i' = start + i;
                #
                if (i' < start or i' >= stop)   raise exception INDEX_OUT_OF_BOUNDS;   fi;
                #
                unsafe_get (base, i');
            };

        fun set (SLICE { base, start, stop }, i, x)
            =
            {   i' = start + i;
                #
                if (i' < start  or   i' >= stop)    raise exception INDEX_OUT_OF_BOUNDS;   fi;
                #
                unsafe_set (base, i', x);
            };

        fun make_full_slice arr
            =
            SLICE { base => arr, start => 0, stop => rw_length arr };

        fun make_slice (arr, start, olen)
            =
            {
                al = rw_length arr;

                SLICE { base =>  arr,
                        #
                        start => if (start < 0 or al < start)  raise exception INDEX_OUT_OF_BOUNDS;
                                 else                          start;
                                 fi,

                        stop => case olen
                                    #
                                    NULL => al;

                                    THE len
                                        =>
                                        {   stop = start +++ len;
                                            #
                                            if (stop < start
                                            or  al < stop
                                            )    raise exception INDEX_OUT_OF_BOUNDS;
                                            else stop;  fi;
                                        };
                                esac
                   };
            };

        fun make_subslice (SLICE { base, start, stop }, i, olen)
            =
            {
                start' = if (i < 0 or stop < i)  raise exception INDEX_OUT_OF_BOUNDS;
                         else                    start +++ i;
                         fi;

                stop' =
                    case olen
                        #
                        NULL => stop;
                        #
                        THE len =>
                            {   stop' =  start' +++ len;
                                #
                                if (stop' < start' or stop < stop')
                                    #
                                    raise exception INDEX_OUT_OF_BOUNDS;
                                else
                                    stop';
                                fi;
                            };
                    esac;

                SLICE { base, start => start', stop => stop' };
            };


        fun burst_slice (SLICE { base, start, stop } )
            =
            (base, start, stop --- start);


        fun copy { src => SLICE { base, start, stop }, dst, di }
            =
            {   sl = stop --- start;
                de = sl + di;

                fun copy_dn (s, d)
                    =
                    if (s >= start)
                        #
                        unsafe_set (dst, d, unsafe_get (base, s));
                        copy_dn (s --- 1, d --- 1);
                    fi;

                fun copy_up (s, d)
                    =
                    if (s < stop)
                        #
                        unsafe_set (dst, d, unsafe_get (base, s));
                        copy_up (s +++ 1, d +++ 1);
                    fi;

                if   (di < 0 or de > rw_length dst)  raise exception INDEX_OUT_OF_BOUNDS;
                elif (di >= start)                   copy_dn (stop --- 1, de --- 1);
                else                                 copy_up (start, di);
                fi;
            };

        fun copy_vec { src => vsl, dst, di }
            =
            {   (vector_slice::burst_slice  vsl)
                    ->
                    (base, start, vlen);

                de = di + vlen;

                fun copy_up (s, d)
                    =
                    if (d < de)
                        #
                        unsafe_set (dst, d, ro_unsafe_get (base, s));
                        copy_up (s +++ 1, d +++ 1);
                    fi;

                if (di < 0 or de > rw_length dst)  raise exception INDEX_OUT_OF_BOUNDS;
                else                               copy_up (start, di);         # Assume vector and rw_vector are disjoint.
                fi;
            };

        fun is_empty (SLICE { start, stop, ... } )
            =
            start == stop;

        fun get_item (SLICE { base, start, stop } )
            =
            if (start >= stop)
                #       
                NULL;
            else
                THE (unsafe_get (base, start),   SLICE { base, start => start +++ 1, stop } );
            fi;

        fun keyed_apply f (SLICE { base, start, stop } )
            =
            apply start
            where
                fun apply i
                    =
                    if (i < stop)
                        #                    
                        f (i --- start, unsafe_get (base, i));
                        apply (i +++ 1);
                    fi;
            end;

        fun apply f (SLICE { base, start, stop } )
            =
            apply start
            where
                fun apply i
                    =
                    if (i < stop)
                        #                    
                        f (unsafe_get (base, i));
                        apply (i +++ 1);
                    fi;
            end;

        fun keyed_map_in_place f (SLICE { base, start, stop } )
            =
            mdf start
            where
                fun mdf i
                    =
                    if (i < stop)
                        #  
                        unsafe_set (base, i, f (i --- start, unsafe_get (base, i)));
                        mdf (i +++ 1);
                    fi;
            end;

        fun map_in_place f (SLICE { base, start, stop } )
            =
            mdf start
            where
                fun mdf i
                    =
                    if (i < stop)
                        #
                        unsafe_set (base, i, f (unsafe_get (base, i)));
                        mdf (i +++ 1);
                    fi;
            end;

        fun keyed_fold_forward f init (SLICE { base, start, stop } )
            =
            fold (start, init)
            where
                fun fold (i, a)
                    =
                    if (i >= stop)   a;
                    else             fold (i +++ 1, f (i --- start, unsafe_get (base, i), a));
                    fi;
            end;

        fun fold_forward f init (SLICE { base, start, stop } )
            =
            fold (start, init)
            where
                fun fold (i, a)
                    =
                    if (i >= stop)   a;
                    else             fold (i +++ 1, f (unsafe_get (base, i), a));
                    fi;
            end;

        fun keyed_fold_backward f init (SLICE { base, start, stop } )
            =
            fold (stop --- 1, init)
            where
                fun fold (i, a)
                    =
                    if (i < start)   a;
                    else             fold (i --- 1, f (i --- start, unsafe_get (base, i), a));
                    fi;
            end;

        fun fold_backward f init (SLICE { base, start, stop } )
            =
            fold (stop --- 1, init)
            where
                fun fold (i, a)
                    =
                    if (i < start)   a;
                    else             fold (i --- 1, f (unsafe_get (base, i), a));
                    fi;
            end;

        fun keyed_find p (SLICE { base, start, stop } )
            =
            fnd start
            where
                fun fnd i
                    =
                    if (i >= stop)
                        #
                        NULL;
                    else
                        x = unsafe_get (base, i);
                        #
                        if (p (i, x))   THE (i --- start, x);
                        else            fnd (i +++ 1);
                        fi;
                    fi;
            end;

        fun find p (SLICE { base, start, stop } )
            =
            fnd start
            where
                fun fnd i
                    =
                    if (i >= stop)
                        #
                        NULL;
                    else
                        x = unsafe_get (base, i);
                        #
                        if (p x)   THE x;
                        else       fnd (i +++ 1);
                        fi;
                    fi;
            end;

        fun exists p (SLICE { base, start, stop } )
            =
            ex start
            where
                fun ex i
                    =
                    i < stop
                    and
                    (   p (unsafe_get (base, i))
                        or
                        ex (i +++ 1)
                    );
            end;

        fun all p (SLICE { base, start, stop } )
            =
            al start
            where
                fun al i
                    =
                    i >= stop
                    or
                    (   p (unsafe_get (base, i))
                        and
                        al (i +++ 1)
                    );
            end;    


        fun compare_sequences c (SLICE { base => b1, start => s1, stop => e1 },
                       SLICE { base => b2, start => s2, stop => e2 } )
        =
        col (s1, s2)
        where
            fun col (i1, i2)
                =
                if (i1 >= e1)
                    #
                    if (i2 >= e2)  EQUAL;
                    else           LESS;
                    fi;
                else
                    if (i2 >= e2)  GREATER;
                    else
                                   case (c (unsafe_get (b1, i1), unsafe_get (b2, i2)))
                                       #
                                       EQUAL   =>  col (i1 +++ 1, i2 +++ 2);
                                       unequal =>  unequal;
                                   esac;
                    fi;
                fi;
        end;

        #  XXX BUGGO FIXME: this is inefficient (going through intermediate list)
        # 
        fun to_vector sl
            =
            case (length sl)
                #
                0   =>  runtime::zero_length_vector__global;
                #
                len =>  runtime::asm::make_typeagnostic_ro_vector  (len, fold_backward (!) [] sl);
            esac;
    };
end;



Comments and suggestions to: bugs@mythryl.org

PreviousUpNext