From 6401b9f3e64fb89e32a39970c65fa2360da53d7e Mon Sep 17 00:00:00 2001 From: moty66 Date: Mon, 14 Oct 2013 09:34:27 +0200 Subject: [PATCH] Catching updates from master --- LICENSE | 38 +-- README.md | 66 ++--- array.axi | 5 + graph.axi | 472 +++++++++++++++++------------------ netlinx-common-libraries.axi | 18 +- test/test_string.axi | 106 ++++---- 6 files changed, 355 insertions(+), 350 deletions(-) diff --git a/LICENSE b/LICENSE index 5046c5a..e88c25b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,19 @@ -Copyright (C) 2011 Queensland Department of Justice and Attorney General. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +Copyright (C) 2011 Queensland Department of Justice and Attorney General. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index 59b29e5..0d4583a 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,33 @@ -This project contains globally useful, portable includes for augmenting the base functionality of the proprietary AMX NetLinx language used for programming [AMX NetLinx integrated controllers](http://www.amx.com/products/categoryCentralControllers.asp). - -Currently the project provides a math library, string manipulation library, time and date library, array utils, a managed debug messaging library and an associated console output library. - -# Contributors -[Kim Burgess](http://kimburgess.info) - -[true](mailto:amx@trueserve.org) - -[Jeff Spire](http://spireintegrated.com/) - -[Jorde Vorstenbosch](mailto:jordevorstenbosch@gmail.com) - -[Andy Dixon](https://github.com/PsyenceFact) - -# Contributing - -Want to help out? Awesome. - -1. Fork it. -2. Make your changes / improvements / bug fixes etc (and ensure that you adhere to the [project style guide](https://github.com/KimBurgess/NetLinx-Common-Libraries/wiki/Code-Format-and-Commenting) whilst doing so). -3. Submit a pull request. -4. Win. - -# Usage - -A convenience include has been provided to simplify usage. Ensure that the libraries are placed within your project's compile path then include prior to utilizing provided functionality within your project code. - - include 'netlinx-common-libraries' - -Alternatively, individually specify the library components that you require. Any cross include dependencies within the NetLinx Common Libraries are handled internally. - -This project is licensed under the MIT License. Feel free to use it, sell it, modify it, re-distribute - basically whatever the hell you like. See [LICENSE](https://github.com/KimBurgess/NetLinx-Common-Libraries/blob/master/LICENSE) for more info. +This project contains globally useful, portable includes for augmenting the base functionality of the proprietary AMX NetLinx language used for programming [AMX NetLinx integrated controllers](http://www.amx.com/products/categoryCentralControllers.asp). + +Currently the project provides a math library, string manipulation library, time and date library, array utils, a managed debug messaging library and an associated console output library. + +# Contributors +[Kim Burgess](http://kimburgess.info) + +[true](mailto:amx@trueserve.org) + +[Jeff Spire](http://spireintegrated.com/) + +[Jorde Vorstenbosch](mailto:jordevorstenbosch@gmail.com) + +[Andy Dixon](https://github.com/PsyenceFact) + +# Contributing + +Want to help out? Awesome. + +1. Fork it. +2. Make your changes / improvements / bug fixes etc (and ensure that you adhere to the [project style guide](https://github.com/KimBurgess/NetLinx-Common-Libraries/wiki/Code-Format-and-Commenting) whilst doing so). +3. Submit a pull request. +4. Win. + +# Usage + +A convenience include has been provided to simplify usage. Ensure that the libraries are placed within your project's compile path then include prior to utilizing provided functionality within your project code. + + include 'netlinx-common-libraries' + +Alternatively, individually specify the library components that you require. Any cross include dependencies within the NetLinx Common Libraries are handled internally. + +This project is licensed under the MIT License. Feel free to use it, sell it, modify it, re-distribute - basically whatever the hell you like. See [LICENSE](https://github.com/KimBurgess/NetLinx-Common-Libraries/blob/master/LICENSE) for more info. diff --git a/array.axi b/array.axi index 0df73e6..16ae13c 100644 --- a/array.axi +++ b/array.axi @@ -4,8 +4,13 @@ program_name='array' include 'math' +include 'io' +define_function array_function_deprecated() { + +} + /** * Finds the index for an matching entry in an array. * diff --git a/graph.axi b/graph.axi index f214b3d..b6aa434 100644 --- a/graph.axi +++ b/graph.axi @@ -1,237 +1,237 @@ -program_name='graph' -#if_not_defined __NCL_LIB_GRAPH -#define __NCL_LIB_GRAPH - - -define_constant -// Bounds for array sizes returned internally. These may be tweaked to optimise -// memory utilization. -GRAPH_MAX_NODES = 128 -GRAPH_MAX_EDGES = 1024 -GRAPH_MAX_ADJACENT_NODES = 16 -GRAPH_MAX_HOPS = 8 - -// Internal constants -GRAPH_NULL_NODE_ID = 0 -GRAPH_MAX_DISTANCE = $FFFF - - -define_type -structure graph_node { - integer id - char settled - integer distance - integer previous -} - -structure graph_edge { - integer id - integer source - integer destination - integer weight -} - -structure graph { - integer nextNodeID - integer nextEdgeID - graph_node nodes[GRAPH_MAX_NODES] - graph_edge edges[GRAPH_MAX_EDGES] -} - - -/** - * Creates a new node in the passed graph. - * - * @param g the graph to create the node in - * @return an integer containing the node ID - */ -define_function integer graph_create_node(graph g) -{ - stack_var graph_node newNode - g.nextNodeID++ - newNode.id = g.nextNodeID - g.nodes[newNode.id] = newNode - set_length_array(g.nodes, g.nextNodeID + 1) - return newNode.id -} - -/** - * Defines a directed edge in the passed graph connecting the supplied edges. - * - * @param g the graph to create the edge in - * @param source the node ID of the edge source - * @param desitination the node ID of the edge desitination - * @param weight the initial weighting to assign to the edge - * @return an integer containing the edge ID - */ -define_function integer graph_create_edge(graph g, integer source, - integer destination, integer weight) -{ - stack_var graph_edge newEdge - g.nextEdgeID++ - newEdge.id = g.nextEdgeID - newEdge.source = source - newEdge.destination = destination - newEdge.weight = weight - g.edges[newEdge.id] = newEdge - set_length_array(g.edges, g.nextEdgeID + 1) - return newEdge.id -} - -/** - * Finds the closest unsettled node in the passed graph. - * - * @param g the graph to search - * @return an integer containg the closest unsettled node ID - */ -define_function integer graph_get_closest_unsettled_node(graph g) { - stack_var integer i - stack_var graph_node n - stack_var graph_node closest - - closest.distance = GRAPH_MAX_DISTANCE - - for (i = 1; i <= length_array(g.nodes); i++) { - n = g.nodes[i] - if (n.settled == false && (n.distance < closest.distance)) { - closest = n - } - } - - return closest.id -} - -/** - * Finds the unsettled neighbours of the passed node. - * - * @param g the graph to search - * @param node the node ID of the node of interest - * @return an array containing the node ID's of adjacent unsettled - * nodes - */ -define_function integer[GRAPH_MAX_ADJACENT_NODES] graph_get_neighbors(graph g, - integer node) -{ - stack_var integer i - stack_var integer j - stack_var integer neighbors[GRAPH_MAX_ADJACENT_NODES] - stack_var graph_edge e - - for (i = length_array(g.edges); i > 0; i--) { - e = g.edges[i] - if (e.destination != GRAPH_NULL_NODE_ID) { - if (e.source == node && g.nodes[e.destination].settled == false) { - j++ - neighbors[j] = e.destination - } - } - } - - set_length_array(neighbors, j) - return neighbors -} - -/** - * Finds the distance (/weight) of the edge connecting the passed nodes. - * - * @param g the graph to search - * @param source the edge source node ID - * @param destination the edge destination node ID - * @return the weight of the joining edge - */ -define_function integer graph_get_distance(graph g, integer source, - integer destination) -{ - stack_var integer i - stack_var graph_edge e - - for (i = 1; i <= length_array(g.edges); i++) { - e = g.edges[i] - if (e.source == source && e.destination == destination) { - return e.weight - } - } - - return GRAPH_MAX_DISTANCE -} - -/** - * Traverse the passed graph and compute all paths from the passed source node. - * - * This uses an implementation of Dijkstra's algorithm. After traversal paths - * are cached within the graph. - * - * @param g the graph to traverse - * @param source the node ID of the source to calculate paths from - */ -define_function graph_compute_paths(graph g, integer source) -{ - stack_var integer i - stack_var integer n - stack_var integer altDist - - for (i = length_array(g.nodes); i > 0; i--) { - g.nodes[i].settled = false - g.nodes[i].distance = GRAPH_MAX_DISTANCE - g.nodes[i].previous = GRAPH_NULL_NODE_ID - } - - g.nodes[source].distance = 0 - - while (true) { - stack_var integer adjacentNodes[GRAPH_MAX_ADJACENT_NODES] - - n = graph_get_closest_unsettled_node(g) - if (n == GRAPH_NULL_NODE_ID) break - if (g.nodes[n].distance == GRAPH_MAX_DISTANCE) break - - g.nodes[n].settled = true - - adjacentNodes = graph_get_neighbors(g, n) - - for (i = 1; i <= length_array(adjacentNodes); i++) { - if (adjacentNodes[i] == GRAPH_NULL_NODE_ID) break - - altDist = g.nodes[n].distance + graph_get_distance(g, n, - adjacentNodes[i]) - if (g.nodes[adjacentNodes[i]].distance > altDist) { - g.nodes[adjacentNodes[i]].distance = altDist - g.nodes[adjacentNodes[i]].previous = n - g.nodes[adjacentNodes[i]].settled = false - } - } - } -} - -/** - * Find the optimum path to the passed destination node based on a previously - * computed graph. - * - * @param g a previously computed (using graph_compute_paths()) - * graph - * @param destination the ID of the destination node to find the path to - * @return an array containing the nodes that form the optimum path - * to the destination node - */ -define_function integer[GRAPH_MAX_HOPS] graph_get_shortest_path(graph g, - integer destination) -{ - stack_var integer path[GRAPH_MAX_HOPS] - stack_var integer step - stack_var integer hop - - step = destination - hop++ - path[hop] = step - - while (g.nodes[step].previous != GRAPH_NULL_NODE_ID) { - step = g.nodes[step].previous - hop++ - path[hop] = step - } - - set_length_array(path, hop) - return path -} - +program_name='graph' +#if_not_defined __NCL_LIB_GRAPH +#define __NCL_LIB_GRAPH + + +define_constant +// Bounds for array sizes returned internally. These may be tweaked to optimise +// memory utilization. +GRAPH_MAX_NODES = 128 +GRAPH_MAX_EDGES = 1024 +GRAPH_MAX_ADJACENT_NODES = 16 +GRAPH_MAX_HOPS = 8 + +// Internal constants +GRAPH_NULL_NODE_ID = 0 +GRAPH_MAX_DISTANCE = $FFFF + + +define_type +structure graph_node { + integer id + char settled + integer distance + integer previous +} + +structure graph_edge { + integer id + integer source + integer destination + integer weight +} + +structure graph { + integer nextNodeID + integer nextEdgeID + graph_node nodes[GRAPH_MAX_NODES] + graph_edge edges[GRAPH_MAX_EDGES] +} + + +/** + * Creates a new node in the passed graph. + * + * @param g the graph to create the node in + * @return an integer containing the node ID + */ +define_function integer graph_create_node(graph g) +{ + stack_var graph_node newNode + g.nextNodeID++ + newNode.id = g.nextNodeID + g.nodes[newNode.id] = newNode + set_length_array(g.nodes, g.nextNodeID + 1) + return newNode.id +} + +/** + * Defines a directed edge in the passed graph connecting the supplied edges. + * + * @param g the graph to create the edge in + * @param source the node ID of the edge source + * @param desitination the node ID of the edge desitination + * @param weight the initial weighting to assign to the edge + * @return an integer containing the edge ID + */ +define_function integer graph_create_edge(graph g, integer source, + integer destination, integer weight) +{ + stack_var graph_edge newEdge + g.nextEdgeID++ + newEdge.id = g.nextEdgeID + newEdge.source = source + newEdge.destination = destination + newEdge.weight = weight + g.edges[newEdge.id] = newEdge + set_length_array(g.edges, g.nextEdgeID + 1) + return newEdge.id +} + +/** + * Finds the closest unsettled node in the passed graph. + * + * @param g the graph to search + * @return an integer containg the closest unsettled node ID + */ +define_function integer graph_get_closest_unsettled_node(graph g) { + stack_var integer i + stack_var graph_node n + stack_var graph_node closest + + closest.distance = GRAPH_MAX_DISTANCE + + for (i = 1; i <= length_array(g.nodes); i++) { + n = g.nodes[i] + if (n.settled == false && (n.distance < closest.distance)) { + closest = n + } + } + + return closest.id +} + +/** + * Finds the unsettled neighbours of the passed node. + * + * @param g the graph to search + * @param node the node ID of the node of interest + * @return an array containing the node ID's of adjacent unsettled + * nodes + */ +define_function integer[GRAPH_MAX_ADJACENT_NODES] graph_get_neighbors(graph g, + integer node) +{ + stack_var integer i + stack_var integer j + stack_var integer neighbors[GRAPH_MAX_ADJACENT_NODES] + stack_var graph_edge e + + for (i = length_array(g.edges); i > 0; i--) { + e = g.edges[i] + if (e.destination != GRAPH_NULL_NODE_ID) { + if (e.source == node && g.nodes[e.destination].settled == false) { + j++ + neighbors[j] = e.destination + } + } + } + + set_length_array(neighbors, j) + return neighbors +} + +/** + * Finds the distance (/weight) of the edge connecting the passed nodes. + * + * @param g the graph to search + * @param source the edge source node ID + * @param destination the edge destination node ID + * @return the weight of the joining edge + */ +define_function integer graph_get_distance(graph g, integer source, + integer destination) +{ + stack_var integer i + stack_var graph_edge e + + for (i = 1; i <= length_array(g.edges); i++) { + e = g.edges[i] + if (e.source == source && e.destination == destination) { + return e.weight + } + } + + return GRAPH_MAX_DISTANCE +} + +/** + * Traverse the passed graph and compute all paths from the passed source node. + * + * This uses an implementation of Dijkstra's algorithm. After traversal paths + * are cached within the graph. + * + * @param g the graph to traverse + * @param source the node ID of the source to calculate paths from + */ +define_function graph_compute_paths(graph g, integer source) +{ + stack_var integer i + stack_var integer n + stack_var integer altDist + + for (i = length_array(g.nodes); i > 0; i--) { + g.nodes[i].settled = false + g.nodes[i].distance = GRAPH_MAX_DISTANCE + g.nodes[i].previous = GRAPH_NULL_NODE_ID + } + + g.nodes[source].distance = 0 + + while (true) { + stack_var integer adjacentNodes[GRAPH_MAX_ADJACENT_NODES] + + n = graph_get_closest_unsettled_node(g) + if (n == GRAPH_NULL_NODE_ID) break + if (g.nodes[n].distance == GRAPH_MAX_DISTANCE) break + + g.nodes[n].settled = true + + adjacentNodes = graph_get_neighbors(g, n) + + for (i = 1; i <= length_array(adjacentNodes); i++) { + if (adjacentNodes[i] == GRAPH_NULL_NODE_ID) break + + altDist = g.nodes[n].distance + graph_get_distance(g, n, + adjacentNodes[i]) + if (g.nodes[adjacentNodes[i]].distance > altDist) { + g.nodes[adjacentNodes[i]].distance = altDist + g.nodes[adjacentNodes[i]].previous = n + g.nodes[adjacentNodes[i]].settled = false + } + } + } +} + +/** + * Find the optimum path to the passed destination node based on a previously + * computed graph. + * + * @param g a previously computed (using graph_compute_paths()) + * graph + * @param destination the ID of the destination node to find the path to + * @return an array containing the nodes that form the optimum path + * to the destination node + */ +define_function integer[GRAPH_MAX_HOPS] graph_get_shortest_path(graph g, + integer destination) +{ + stack_var integer path[GRAPH_MAX_HOPS] + stack_var integer step + stack_var integer hop + + step = destination + hop++ + path[hop] = step + + while (g.nodes[step].previous != GRAPH_NULL_NODE_ID) { + step = g.nodes[step].previous + hop++ + path[hop] = step + } + + set_length_array(path, hop) + return path +} + #end_if \ No newline at end of file diff --git a/netlinx-common-libraries.axi b/netlinx-common-libraries.axi index 815b4f2..14d69d5 100644 --- a/netlinx-common-libraries.axi +++ b/netlinx-common-libraries.axi @@ -1,9 +1,9 @@ -program_name='ncl' - -include 'io' -include 'debug' -include 'array' -include 'string' -include 'math' -include 'unixtime' -include 'graph' +program_name='ncl' + +include 'io' +include 'debug' +include 'array' +include 'string' +include 'math' +include 'unixtime' +include 'graph' diff --git a/test/test_string.axi b/test/test_string.axi index 41e8beb..2221de5 100644 --- a/test/test_string.axi +++ b/test/test_string.axi @@ -1,54 +1,54 @@ -program_name='test_string' -#if_not_defined __NCL_LIB_TEST_STRING -#define __NCL_LIB_TEST_STRING - -include 'string' -include 'io' -include 'test_utils' - - -define_constant - long TEST_STRING_ITERATIONS = 100 // number of times to execute each - // test for speed testing - -define_function char test_string_get_between(char a[], - char left[], char right[]) -{ - stack_var long i - - println("'Running string_get_between(',a, ',',left,', ',right,')'") - test_timer_start() - for (i = TEST_STRING_ITERATIONS; i; i--) { - string_get_between(a, left, right) - } - test_timer_stop(TEST_STRING_ITERATIONS) - return test_end(); -} - -define_function char test_string_ci_get_between(char a[], - char left[], char right[]) -{ - stack_var long i - - println("'Running string_ci_get_between(',a, ',',left,', ',right,')'") - test_timer_start() - for (i = TEST_STRING_ITERATIONS; i; i--) { - string_ci_get_between(a, left, right) - } - test_timer_stop(TEST_STRING_ITERATIONS) - return test_end(); -} - -/** - * Test functionality of some string functions - */ -define_function test_string() -{ - println("':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'") - println("'Running string library test suite.'") - println("' '") - test_string_get_between('http://site.com/', 'http://', '/'); - test_string_ci_get_between('http://site.com/', 'HTTP://', '/'); -} - +program_name='test_string' +#if_not_defined __NCL_LIB_TEST_STRING +#define __NCL_LIB_TEST_STRING + +include 'string' +include 'io' +include 'test_utils' + + +define_constant + long TEST_STRING_ITERATIONS = 100 // number of times to execute each + // test for speed testing + +define_function char test_string_get_between(char a[], + char left[], char right[]) +{ + stack_var long i + + println("'Running string_get_between(',a, ',',left,', ',right,')'") + test_timer_start() + for (i = TEST_STRING_ITERATIONS; i; i--) { + string_get_between(a, left, right) + } + test_timer_stop(TEST_STRING_ITERATIONS) + return test_end(); +} + +define_function char test_string_ci_get_between(char a[], + char left[], char right[]) +{ + stack_var long i + + println("'Running string_ci_get_between(',a, ',',left,', ',right,')'") + test_timer_start() + for (i = TEST_STRING_ITERATIONS; i; i--) { + string_ci_get_between(a, left, right) + } + test_timer_stop(TEST_STRING_ITERATIONS) + return test_end(); +} + +/** + * Test functionality of some string functions + */ +define_function test_string() +{ + println("':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::'") + println("'Running string library test suite.'") + println("' '") + test_string_get_between('http://site.com/', 'http://', '/'); + test_string_ci_get_between('http://site.com/', 'HTTP://', '/'); +} + #end_if \ No newline at end of file