/* *********************************************************************
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
);;