/* ********************************************************************* This source file is a part of the standard library of Scol For the latest info, see http://www.scolring.org Copyright (c) 2013 Stephane Bisaro aka Iri Some functions has been originally written to the Openspace3d project. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt ********************************************************************* */ /* * Standard functions for array (tab) * See http://redmine.scolring.org/projects/tutorials/wiki/Scol_usage * for more informations */ /*! \file tab.pkg * \author Scol team * \version 0.1 * \copyright GNU Lesser General Public License 2.0 or later * \brief Scol Standard Library - Table API * * \details This API provides an high level method to easily manage a table * **/ /*! \brief Create an array and fill it * * \ingroup std_table * Prototype: fun [I fun [I u0] u1 u0] tab u1 * * \param I : the size of the array * \param fun [I u0] u1 : function called to fill each element (the integer is the index) * \param u0 : an user parameter to fill the array * * \return tab u1 : the new array **/ fun std_tabCreate (size, f, x)= let mktab size nil -> t in let 0 -> i in ( while i < size do ( set t.i = exec f with [i x]; set i = i + 1 ); t );; fun std_tabcheckindex (tab, index)= ((index >= 0) && (index < sizetab tab));; fun std_tabindexpositive (tab, index)= if index < 0 then (sizetab tab) + index else index;; /*! \brief Get the appropriate value to an index. * The function verify if the index is not out of range. * * \ingroup std_table * Prototype: fun [tab u0 I] u0 * * \param tab u0 : a table * \param I : an index * * \return u0 : the value or nil if the index is out of range (but the * value can be nil itself) **/ fun std_tabGet (tab, index)= if !std_tabcheckindex tab index then nil else tab.index;; /*! \brief Set the value to an index. * The function verify if the index is not out of range. * * \ingroup std_table * Prototype: fun [tab u0 I u0] u0 * * \param tab u0 : a table * \param I : an index * \param u0 : the value * * \return u0 : the same value or nil if the index is out of range (but the * value can be nil itself) **/ fun std_tabSet (tab, index, value)= if !std_tabcheckindex tab index then nil else set tab.index = value;; /*! \brief Compare a value of an index with a given value. * All types are supported except S (string). For the last case, \see std_tabCmpStr * * \ingroup std_table * Prototype: fun [tab u0 I u0] I * * \param tab u0 : a table * \param I : an index * \param u0 : the value to compare * * \return I : 1 if equal, 0 if not equal or nil if the index is out of * range **/ fun std_tabCmp (tab, index, value)= if !std_tabcheckindex tab index then nil else tab.index == value;; /*! \brief Compare a string of an index with a given string. * * \ingroup std_table * Prototype: fun [tab S I S] I * * \param tab S : a table * \param I : an index * \param S : the value to compare * * \return I : 0 if equal, a negative or positive value if different * or nil if the index is out of range **/ fun std_tabCmpStr (tab, index, string)= if !std_tabcheckindex tab index then nil else strcmp tab.index string;; /*! \brief Compare all values from an index until a lenght between two tables. * The first index is always 0 in a table. * All types are supported except S (string). For the last case, \see std_tabCmpUntilStr * * \ingroup std_table * Prototype: fun [tab u0 tab u0 I I] I * * \param tab u0 : a table * \param tab u0 : another table * \param I : an index to start * \param I : a length to the end * * \return I : 1 if equal, 0 if not equal **/ fun std_tabCmpUntil (tab1, tab2, from, len)= let sizetab tab1 -> size1 in let sizetab tab2 -> size2 in ( set from = if size1 > size2 then std_tabindexpositive tab2 from else std_tabindexpositive tab1 from; if ((from > size1-1) || (from > size2-1)) then 0 else if (((from+len) > size1-1) || ((from+len) > size2-1)) then 0 else let from -> i in let 1 -> r in ( while ((i <= len) && (r == 1)) do if tab1.i != tab2.i then set r = 0 else set i = i+1; r ) );; fun std_tabcmpuntilstr (tab1, tab2, from, len, isSensitive)= let sizetab tab1 -> size1 in let sizetab tab2 -> size2 in let len -> to in ( set from = if size1 > size2 then std_tabindexpositive tab2 from else std_tabindexpositive tab1 from; set to = from+len; if ((from > size1-1) || (from > size2-1)) then 0 else if (((from+len) > size1) || ((from+len) > size2)) then 0 else let from -> i in let 1 -> r in ( while ((i < to) && (r == 1)) do if ((!std_tabcheckindex tab1 i) || (!std_tabcheckindex tab2 i)) then set r = nil else if (((isSensitive) && (!strcmp tab1.i tab2.i)) || ((!isSensitive) && (!strcmpi tab1.i tab2.i))) then set i = i+1 else set r = 0; r ) );; /*! \brief Compare all strings from an index until a lenght between two tables. * Function case-sensitive. * The first index is always 0 in a table. * * \ingroup std_table * Prototype: fun [tab S tab S I I] I * * \param tab S : a table * \param tab S : another table * \param I : an index to start * \param I : a length to the end * * \return I : 1 if equal, 0 if not equal (nil if internal error) **/ fun std_tabCmpUntilStr (tab1, tab2, from, len)= std_tabcmpuntilstr tab1 tab2 from len 1;; /*! \brief Compare all strings from an index until a lenght between two tables. * Function case-insensitive. * The first index is always 0 in a table. * * \ingroup std_table * Prototype: fun [tab S tab S I I] I * * \param tab S : a table * \param tab S : another table * \param I : an index to start * \param I : a length to the end * * \return I : 1 if equal, 0 if not equal (nil if internal error) **/ fun std_tabCmpUntilStri (tab1, tab2, from, len)= std_tabcmpuntilstr tab1 tab2 from len 0;; fun std_tabfind (tab, size, i, value)= if !std_tabcheckindex tab i then nil else let tab.i -> e in if e == value then i else std_tabfind tab size i+1 value;; /*! \brief Searches a value in a table from a position. To find all results, * this function can be called from a loop/recursive function. * The first index is always 0 in a table. * All types are supported except S (string). For the last case, \see std_tabFindStr * * \ingroup std_table * Prototype: fun [tab u0 u0 I] I * * \param tab u0 : a table * \param u0 : a value to find * \param I : an index to start * * \return I : the index where the value has been found or nil if not found or error **/ fun std_tabFind (tab, value, from)= set from = std_tabindexpositive tab from; let sizetab tab -> size in if (from >= size-1) then nil else std_tabfind tab size from value;; fun std_tabfindstr (tab, size, i, str, isSensitive)= if !std_tabcheckindex tab i then nil else let tab.i -> e in if (((isSensitive) && (!strcmp e str)) || ((!isSensitive) && (!strcmpi e str))) then i else std_tabfindstr tab size i+1 str isSensitive;; /*! \brief Searches a string in a table from a position. To find all results, * this function can be called from a loop/recursive function. * The first index is always 0 in a table. * * \ingroup std_table * \remark : this function is case-sensitive. * * Prototype: fun [tab S S I] I * * \param tab S : a table * \param S : a value to find * \param I : an index to start * * \return I : the index where the value has been found or nil if not found or error **/ fun std_tabFindStr (tab, str, from)= set from = std_tabindexpositive tab from; let sizetab tab -> size in if (from >= size-1) then nil else std_tabfindstr tab size from str 1;; /*! \brief Searches a string in a table from a position. To find all results, * this function can be called from a loop/recursive function. * The first index is always 0 in a table. * * \ingroup std_table * \remark : this function is case-insensitive. * * Prototype: fun [tab S S I] I * * \param tab S : a table * \param S : a value to find * \param I : an index to start * * \return I : the index where the value has been found or nil if not found or error **/ fun std_tabFindStri (tab, str, from)= set from = std_tabindexpositive tab from; let sizetab tab -> size in if (from >= size-1) then nil else std_tabfindstr tab size from str 0;; /*! \brief Clear all values of a table to nil. * * \ingroup std_table * \remark : the size is unchanged, a table has always a fixed size ! * Only values are nil. * * Prototype: fun [tab u0] tab u0 * * \return tab u0 : the cleared table **/ fun std_tabClear (tab)= let (sizetab tab) - 1 -> i in while i >= 0 do ( set tab.i = nil; set i = i - 1 ); tab;; /*! \brief Reset all values of a table * * \ingroup std_table * Prototype: fun [tab u1 fun [I u0] u1 u0] tab u1 * * \param tab u1 : a table already created * \param fun [I u0] u1 : function called to fill each element (the integer is the index) * \param u0 : an user parameter to fill the array * * \return tab u1 : the reset table **/ fun std_tabReset (tab, f, x)= let (sizetab tab) - 1 -> i in while i >= 0 do ( set tab.i = exec f with [i x]; set i = i - 1 ); tab;; /*! \brief Copy values of a table in a new table * If the size of the table is smaller than the size of the new table, all * other indexes are nil. * * \ingroup std_table * Prototype: fun [tab u0 I] tab u0 * * \param tab u0 : a table already created * \param I : the size of the new table * * \return tab u0 : the new table or nil if error **/ fun std_tabCopy (tab, size)= if ((tab == nil) || (size <= 0)) then nil else let mktab size nil -> newtab in let 0 -> i in let (sizetab tab) - 1 -> len in let if len <= size then len else size -> s in ( while i <= s do if ((!std_tabcheckindex tab i) || (!std_tabcheckindex newtab i)) then set i = s+1 else ( set newtab.i = tab.i; set i = i + 1; ); newtab );;