Merge branch 'master' into feature/stats
Conflicts: bench.html bench_str.csv config.h config.h.in include/r3.h src/node.c
This commit is contained in:
commit
76e4b15787
23 changed files with 382 additions and 1152 deletions
|
@ -28,7 +28,7 @@ script:
|
||||||
- make V=1
|
- make V=1
|
||||||
- sudo make install
|
- sudo make install
|
||||||
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
|
- if [ "x$VALGRIND" == xyes ]; then make check > /dev/null 2>&1; else make check V=1; fi
|
||||||
- if [ "x$VALGRIND" == xyes ]; then valgrind ./tests/.libs/* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
|
- if [ "x$VALGRIND" == xyes ]; then valgrind ./tests/.libs/check_* -v --trace-children=yes --show-leak-kinds=full --leak-check=full; fi
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- if [ x$COVERALLS == xyes ]; then coveralls ; fi
|
- if [ x$COVERALLS == xyes ]; then coveralls ; fi
|
||||||
|
|
42
README.md
42
README.md
|
@ -120,9 +120,35 @@ r3_route_free(r1);
|
||||||
r3_tree_free(n);
|
r3_tree_free(n);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Slug
|
||||||
|
-----------------------
|
||||||
|
A slug is a placeholder, which captures the string from the URL as a variable.
|
||||||
|
Slugs will be compiled into regular expression patterns.
|
||||||
|
|
||||||
|
Slugs without specified pattern (like `/user/{userId}`) will be compiled with the `[^/]+` pattern.
|
||||||
|
|
||||||
|
To specify the pattern of a slug, you may write a colon to separate the slug name and the pattern:
|
||||||
|
|
||||||
|
"/user/{userId:\\d+}"
|
||||||
|
|
||||||
|
The above route will use `\d+` as its pattern.
|
||||||
|
|
||||||
|
|
||||||
Benchmark
|
Optimization
|
||||||
|
-----------------------
|
||||||
|
Simple regular expressions are optimized through a regexp pattern to opcode
|
||||||
|
compiler, which translates simple patterns into small & fast scanners.
|
||||||
|
|
||||||
|
By using this method, r3 reduces the matching overhead of pcre library.
|
||||||
|
|
||||||
|
Optimized patterns are: `[a-z]+`, `[0-9]+`, `\d+`, `\w+`, `[^/]+` or `[^-]+`
|
||||||
|
|
||||||
|
slugs without specified regular expression will be compiled with a `[^/]+` pattern. therefore, it's optimized too.
|
||||||
|
|
||||||
|
Complex regular expressions will still use libpcre to match URL (partially).
|
||||||
|
|
||||||
|
|
||||||
|
Performance
|
||||||
-----------------------
|
-----------------------
|
||||||
The routing benchmark from stevegraham/rails' PR <https://github.com/stevegraham/rails/pull/1>:
|
The routing benchmark from stevegraham/rails' PR <https://github.com/stevegraham/rails/pull/1>:
|
||||||
|
|
||||||
|
@ -151,6 +177,19 @@ paths.each do |path|
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Function prefix mapping
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
|Function Prefix |Description |
|
||||||
|
|------------------|------------------------------------------------------------------------------------|
|
||||||
|
|`r3_tree_*` |Tree related operations, which require a node to operate a whole tree |
|
||||||
|
|`r3_node_*` |Single node related operations, which do not go through its own children or parent. |
|
||||||
|
|`r3_edge_*` |Edge related operations |
|
||||||
|
|`r3_route_*` |Route related operations, which are needed only when the tree is defined by routes |
|
||||||
|
|`match_entry_*` |Match entry related operations, a `match_entry` is just like the request parameters |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Rendering routes with graphviz
|
Rendering routes with graphviz
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
@ -176,6 +215,7 @@ digraph g {
|
||||||
|
|
||||||
Use case in PHP
|
Use case in PHP
|
||||||
-----------------------
|
-----------------------
|
||||||
|
**not implemented yet**
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Here is the paths data structure
|
// Here is the paths data structure
|
||||||
|
|
20
bench.html
20
bench.html
|
@ -9,7 +9,7 @@
|
||||||
<script src="http://code.highcharts.com/modules/exporting.js"></script>
|
<script src="http://code.highcharts.com/modules/exporting.js"></script>
|
||||||
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
|
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
|
||||||
<script>
|
<script>
|
||||||
$.get('tests/bench_str.csv', function(data) {
|
$.get('bench_str.csv', function(data) {
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
chart: {
|
chart: {
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'area',
|
type: 'area',
|
||||||
name: '/post/{year}/{month}',
|
name: 'simple pattern matching',
|
||||||
pointInterval: 1000,
|
pointInterval: 1000,
|
||||||
lineWidth: 1,
|
lineWidth: 1,
|
||||||
marker: {
|
marker: {
|
||||||
|
@ -164,6 +164,17 @@
|
||||||
},
|
},
|
||||||
pointStart: Date.UTC(2014, 5, 16),
|
pointStart: Date.UTC(2014, 5, 16),
|
||||||
data: []
|
data: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'area',
|
||||||
|
name: 'match_entry with str',
|
||||||
|
pointInterval: 1000,
|
||||||
|
lineWidth: 1,
|
||||||
|
marker: {
|
||||||
|
radius: 3
|
||||||
|
},
|
||||||
|
pointStart: Date.UTC(2014, 5, 16),
|
||||||
|
data: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -179,9 +190,8 @@
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
var columns = line.split(/,/);
|
var columns = line.split(/,/);
|
||||||
|
var commentText = columns[5];
|
||||||
var commentText = columns[4];
|
for (var i = 1; i < 5; i++ ) {
|
||||||
for (var i = 1; i < 4; i++ ) {
|
|
||||||
var a = parseInt(columns[i]);
|
var a = parseInt(columns[i]);
|
||||||
var args = a ?
|
var args = a ?
|
||||||
(commentText ? { y: a, comment: commentText } : a)
|
(commentText ? { y: a, comment: commentText } : a)
|
||||||
|
|
|
@ -461,7 +461,70 @@
|
||||||
1400750512,10126746.58
|
1400750512,10126746.58
|
||||||
1400750536,10568568.26
|
1400750536,10568568.26
|
||||||
1400762875,10472029.42
|
1400762875,10472029.42
|
||||||
1400764426,10066458.45,1590373.41,0,flag
|
1400764426,10066458.45,1590373.41
|
||||||
1400765068,10657617.64,2131810.12,0,flag
|
1400765068,10657617.64,2131810.12
|
||||||
1400766518,10259200.94,1878279.25,96697.86,flag1
|
1400766518,10259200.94,1878279.25,96697.86
|
||||||
1400766623,11057429.08,2113683.19,95835.70,flag2
|
1400766623,11057429.08,2113683.19,95835.70
|
||||||
|
1400815975,11316714.26,2165050.14,55188.21
|
||||||
|
1400815990,10826986.93,1780938.43,55188.21
|
||||||
|
1400816005,10584527.76,1707721.44,55924.05
|
||||||
|
1400816427,9376611.56,2006568.41,53092.46
|
||||||
|
1400816438,9096902.53,2108994.21,59074.70
|
||||||
|
1400816448,9260790.48,2131479.91,55188.21
|
||||||
|
1400816458,9303957.38,2110797.39,55924.05
|
||||||
|
1400816525,9330370.85,1985782.06,59074.70
|
||||||
|
1400816594,9389101.94,1989498.64,34663.67
|
||||||
|
1400816645,9201251.49,2105517.01,43240.25
|
||||||
|
1400816815,9228390.29,2097606.06,23301.69
|
||||||
|
1400817268,9242018.45,2109706.16,38479.85
|
||||||
|
1400817280,9320308.27,1891100.64,47662.55
|
||||||
|
1400817392,6448229.88,1994875.02,34663.67
|
||||||
|
1400817671,8654311.52,2094510.75,47662.55
|
||||||
|
1400817706,9362050.27,1981074.38,62601.55
|
||||||
|
1400818067,9247601.69,1944615.34,35848.75
|
||||||
|
1400818654,10797650.12,2550647.32,52428.80
|
||||||
|
1400818717,10964008.21,2607023.59,59074.70
|
||||||
|
1400818725,11160125.46,2574373.69,47127.01
|
||||||
|
1400818732,10829199.02,2557782.44,67650.06
|
||||||
|
1400818739,10859734.88,2538368.71,41527.76
|
||||||
|
1400820693,12547680.62,2375764.20,55924.05
|
||||||
|
1400820703,12815067.19,2375474.47,34379.54
|
||||||
|
1400820719,11693810.54,2231143.55,47662.55
|
||||||
|
1400820728,12612875.15,2357108.19,49932.19
|
||||||
|
1400820868,12158497.75,2598723.80,62601.55
|
||||||
|
1400820877,12254639.62,2583601.86,77672.30
|
||||||
|
1400820886,12274457.34,2393445.83,55188.21
|
||||||
|
1400820922,12218386.22,2604565.56,77672.30
|
||||||
|
1400820933,12443155.46,2361317.46,45590.26
|
||||||
|
1400829105,12110496.08,4797414.85,38479.85
|
||||||
|
1400829117,12258758.55,4129968.45,59074.70
|
||||||
|
1400829143,12339827.27,4775224.01,55924.05
|
||||||
|
1400831278,11421287.15,4742488.93,39945.75
|
||||||
|
1400832805,11676305.28,4832961.50,58254.22
|
||||||
|
1400832811,11785948.52,4137657.27,45590.26
|
||||||
|
1400832831,11918383.46,4859275.06,47662.55
|
||||||
|
1400832837,11650937.22,4734982.85,61680.94
|
||||||
|
1400832892,11728021.34,4274247.24,45590.26
|
||||||
|
1400832912,11580034.68,4752494.99,62601.55
|
||||||
|
1400833017,11890578.32,4501803.27,29330.80
|
||||||
|
1400833024,11715363.55,4726544.41,59074.70
|
||||||
|
1400833045,11813359.08,4828190.72,53092.46
|
||||||
|
1400833051,11082009.03,4721512.49,62601.55
|
||||||
|
1400837359,2709622.75,4773140.52,71089.90
|
||||||
|
1400837501,11958680.82,4777890.52,45590.26
|
||||||
|
1400837621,11423775.75,4679207.46,59074.70,2459430.07
|
||||||
|
1400837636,11534281.98,4192617.73,66576.25,2968590.57
|
||||||
|
1400837657,11693260.66,4815393.82,77672.30,2856236.96
|
||||||
|
1400837667,11834338.05,4822006.81,47662.55,3015821.63
|
||||||
|
1400837677,11999462.15,4854783.73,49932.19,3008349.32
|
||||||
|
1400837696,11814938.63,4740948.30,55188.21,3007002.06
|
||||||
|
1400837706,11535595.30,4712420.14,62601.55,2865728.03
|
||||||
|
1400837716,11928552.18,4833449.01,35848.75,2990344.18
|
||||||
|
1400837725,11873673.72,4275934.73,45590.26,3024045.98
|
||||||
|
1400837735,11805064.50,4855078.95,47662.55,3016256.98
|
||||||
|
1400837744,12041094.07,4815428.09,61680.94,2991090.14
|
||||||
|
1400837754,11766504.83,4848425.07,47662.55,2986385.66
|
||||||
|
1400837764,11979089.24,4257134.48,47662.55,3015693.70
|
||||||
|
1400837774,11190990.08,4331119.44,45590.26,2587281.10
|
||||||
|
1400837785,10306507.50,3909290.89,47662.55,2827471.10
|
||||||
|
1400837797,10323334.38,4221122.48,55924.05,2294463.55
|
Can't render this file because it has a wrong number of fields in line 464.
|
|
@ -1,54 +0,0 @@
|
||||||
# - Try to find the CHECK libraries
|
|
||||||
# Once done this will define
|
|
||||||
#
|
|
||||||
# CHECK_FOUND - system has check
|
|
||||||
# CHECK_INCLUDE_DIRS - the check include directory
|
|
||||||
# CHECK_LIBRARIES - check library
|
|
||||||
#
|
|
||||||
# Copyright (c) 2007 Daniel Gollub <gollub@b1-systems.de>
|
|
||||||
# Copyright (c) 2007-2009 Bjoern Ricks <bjoern.ricks@gmail.com>
|
|
||||||
#
|
|
||||||
# Redistribution and use is allowed according to the terms of the New
|
|
||||||
# BSD license.
|
|
||||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
|
||||||
|
|
||||||
|
|
||||||
INCLUDE( FindPkgConfig )
|
|
||||||
|
|
||||||
IF ( Check_FIND_REQUIRED )
|
|
||||||
SET( _pkgconfig_REQUIRED "REQUIRED" )
|
|
||||||
ELSE( Check_FIND_REQUIRED )
|
|
||||||
SET( _pkgconfig_REQUIRED "" )
|
|
||||||
ENDIF ( Check_FIND_REQUIRED )
|
|
||||||
|
|
||||||
IF ( CHECK_MIN_VERSION )
|
|
||||||
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check>=${CHECK_MIN_VERSION} )
|
|
||||||
ELSE ( CHECK_MIN_VERSION )
|
|
||||||
PKG_SEARCH_MODULE( CHECK ${_pkgconfig_REQUIRED} check )
|
|
||||||
ENDIF ( CHECK_MIN_VERSION )
|
|
||||||
|
|
||||||
# Look for CHECK include dir and libraries
|
|
||||||
IF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
|
|
||||||
|
|
||||||
FIND_PATH( CHECK_INCLUDE_DIRS check.h )
|
|
||||||
|
|
||||||
FIND_LIBRARY( CHECK_LIBRARIES NAMES check )
|
|
||||||
|
|
||||||
IF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
|
||||||
SET( CHECK_FOUND 1 )
|
|
||||||
IF ( NOT Check_FIND_QUIETLY )
|
|
||||||
MESSAGE ( STATUS "Found CHECK: ${CHECK_LIBRARIES}" )
|
|
||||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
|
||||||
ELSE ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
|
||||||
IF ( Check_FIND_REQUIRED )
|
|
||||||
MESSAGE( FATAL_ERROR "Could NOT find CHECK" )
|
|
||||||
ELSE ( Check_FIND_REQUIRED )
|
|
||||||
IF ( NOT Check_FIND_QUIETLY )
|
|
||||||
MESSAGE( STATUS "Could NOT find CHECK" )
|
|
||||||
ENDIF ( NOT Check_FIND_QUIETLY )
|
|
||||||
ENDIF ( Check_FIND_REQUIRED )
|
|
||||||
ENDIF ( CHECK_INCLUDE_DIRS AND CHECK_LIBRARIES )
|
|
||||||
ENDIF( NOT CHECK_FOUND AND NOT PKG_CONFIG_FOUND )
|
|
||||||
|
|
||||||
# Hide advanced variables from CMake GUIs
|
|
||||||
MARK_AS_ADVANCED( CHECK_INCLUDE_DIRS CHECK_LIBRARIES )
|
|
|
@ -1,44 +0,0 @@
|
||||||
# - Try to find jemalloc headers and libraries.
|
|
||||||
#
|
|
||||||
# Usage of this module as follows:
|
|
||||||
#
|
|
||||||
# find_package(JeMalloc)
|
|
||||||
#
|
|
||||||
# Variables used by this module, they can change the default behaviour and need
|
|
||||||
# to be set before calling find_package:
|
|
||||||
#
|
|
||||||
# JEMALLOC_ROOT_DIR Set this variable to the root installation of
|
|
||||||
# jemalloc if the module has problems finding
|
|
||||||
# the proper installation path.
|
|
||||||
#
|
|
||||||
# Variables defined by this module:
|
|
||||||
#
|
|
||||||
# JEMALLOC_FOUND System has jemalloc libs/headers
|
|
||||||
# JEMALLOC_LIBRARIES The jemalloc library/libraries
|
|
||||||
# JEMALLOC_INCLUDE_DIR The location of jemalloc headers
|
|
||||||
|
|
||||||
find_path(JEMALLOC_ROOT_DIR
|
|
||||||
NAMES include/jemalloc/jemalloc.h
|
|
||||||
)
|
|
||||||
|
|
||||||
find_library(JEMALLOC_LIBRARIES
|
|
||||||
NAMES jemalloc
|
|
||||||
HINTS ${JEMALLOC_ROOT_DIR}/lib
|
|
||||||
)
|
|
||||||
|
|
||||||
find_path(JEMALLOC_INCLUDE_DIR
|
|
||||||
NAMES jemalloc/jemalloc.h
|
|
||||||
HINTS ${JEMALLOC_ROOT_DIR}/include
|
|
||||||
)
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(JeMalloc DEFAULT_MSG
|
|
||||||
JEMALLOC_LIBRARIES
|
|
||||||
JEMALLOC_INCLUDE_DIR
|
|
||||||
)
|
|
||||||
|
|
||||||
mark_as_advanced(
|
|
||||||
JEMALLOC_ROOT_DIR
|
|
||||||
JEMALLOC_LIBRARIES
|
|
||||||
JEMALLOC_INCLUDE_DIR
|
|
||||||
)
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Copyright (C) 2007-2009 LuaDist.
|
|
||||||
# Created by Peter Kapec <kapecp@gmail.com>
|
|
||||||
# Redistribution and use of this file is allowed according to the terms of the MIT license.
|
|
||||||
# For details see the COPYRIGHT file distributed with LuaDist.
|
|
||||||
# Note:
|
|
||||||
# Searching headers and libraries is very simple and is NOT as powerful as scripts
|
|
||||||
# distributed with CMake, because LuaDist defines directories to search for.
|
|
||||||
# Everyone is encouraged to contact the author with improvements. Maybe this file
|
|
||||||
# becomes part of CMake distribution sometimes.
|
|
||||||
|
|
||||||
# - Find judy
|
|
||||||
# Find the native Judy headers and libraries.
|
|
||||||
#
|
|
||||||
# Judy_INCLUDE_DIRS - where to find judy.h, etc.
|
|
||||||
# Judy_LIBRARIES - List of libraries when using judy.
|
|
||||||
# Judy_FOUND - True if judy found.
|
|
||||||
|
|
||||||
# Look for the header file.
|
|
||||||
FIND_PATH(Judy_INCLUDE_DIR NAMES Judy.h)
|
|
||||||
|
|
||||||
# Look for the library.
|
|
||||||
FIND_LIBRARY(Judy_LIBRARY NAMES judy)
|
|
||||||
|
|
||||||
# Handle the QUIETLY and REQUIRED arguments and set Judy_FOUND to TRUE if all listed variables are TRUE.
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Judy DEFAULT_MSG Judy_LIBRARY Judy_INCLUDE_DIR)
|
|
||||||
|
|
||||||
# Copy the results to the output variables.
|
|
||||||
IF(Judy_FOUND)
|
|
||||||
SET(Judy_LIBRARIES ${Judy_LIBRARY})
|
|
||||||
SET(Judy_INCLUDE_DIRS ${Judy_INCLUDE_DIR})
|
|
||||||
ELSE(Judy_FOUND)
|
|
||||||
SET(Judy_LIBRARIES)
|
|
||||||
SET(Judy_INCLUDE_DIRS)
|
|
||||||
ENDIF(Judy_FOUND)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(Judy_INCLUDE_DIRS Judy_LIBRARIES)
|
|
|
@ -1,37 +0,0 @@
|
||||||
# Copyright (C) 2007-2009 LuaDist.
|
|
||||||
# Created by Peter Kapec <kapecp@gmail.com>
|
|
||||||
# Redistribution and use of this file is allowed according to the terms of the MIT license.
|
|
||||||
# For details see the COPYRIGHT file distributed with LuaDist.
|
|
||||||
# Note:
|
|
||||||
# Searching headers and libraries is very simple and is NOT as powerful as scripts
|
|
||||||
# distributed with CMake, because LuaDist defines directories to search for.
|
|
||||||
# Everyone is encouraged to contact the author with improvements. Maybe this file
|
|
||||||
# becomes part of CMake distribution sometimes.
|
|
||||||
|
|
||||||
# - Find pcre
|
|
||||||
# Find the native PCRE headers and libraries.
|
|
||||||
#
|
|
||||||
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
|
|
||||||
# PCRE_LIBRARIES - List of libraries when using pcre.
|
|
||||||
# PCRE_FOUND - True if pcre found.
|
|
||||||
|
|
||||||
# Look for the header file.
|
|
||||||
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcre.h)
|
|
||||||
|
|
||||||
# Look for the library.
|
|
||||||
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
|
|
||||||
|
|
||||||
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
|
|
||||||
INCLUDE(FindPackageHandleStandardArgs)
|
|
||||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_INCLUDE_DIR)
|
|
||||||
|
|
||||||
# Copy the results to the output variables.
|
|
||||||
IF(PCRE_FOUND)
|
|
||||||
SET(PCRE_LIBRARIES ${PCRE_LIBRARY})
|
|
||||||
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
|
|
||||||
ELSE(PCRE_FOUND)
|
|
||||||
SET(PCRE_LIBRARIES)
|
|
||||||
SET(PCRE_INCLUDE_DIRS)
|
|
||||||
ENDIF(PCRE_FOUND)
|
|
||||||
|
|
||||||
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)
|
|
122
config.h
122
config.h
|
@ -1,122 +0,0 @@
|
||||||
/* config.h. Generated from config.h.in by configure. */
|
|
||||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
|
||||||
|
|
||||||
/* "whether graphviz is enable" */
|
|
||||||
#define ENABLE_GRAPHVIZ test "x$enable_graphviz" = "xyes"
|
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
/* "whether statistics is enable" */
|
|
||||||
#define ENABLE_STATS test "x$enable_stats" = "xyes"
|
|
||||||
=======
|
|
||||||
>>>>>>> master
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
|
||||||
#define HAVE_DLFCN_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `gettimeofday' function. */
|
|
||||||
#define HAVE_GETTIMEOFDAY 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
|
||||||
#define HAVE_INTTYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <jemalloc/jemalloc.h> header file. */
|
|
||||||
/* #undef HAVE_JEMALLOC_JEMALLOC_H */
|
|
||||||
|
|
||||||
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
|
|
||||||
to 0 otherwise. */
|
|
||||||
#define HAVE_MALLOC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <memory.h> header file. */
|
|
||||||
#define HAVE_MEMORY_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `memset' function. */
|
|
||||||
#define HAVE_MEMSET 1
|
|
||||||
|
|
||||||
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
|
|
||||||
and to 0 otherwise. */
|
|
||||||
#define HAVE_REALLOC 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdint.h> header file. */
|
|
||||||
#define HAVE_STDINT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
|
||||||
#define HAVE_STDLIB_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strchr' function. */
|
|
||||||
#define HAVE_STRCHR 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strdup' function. */
|
|
||||||
#define HAVE_STRDUP 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <strings.h> header file. */
|
|
||||||
#define HAVE_STRINGS_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <string.h> header file. */
|
|
||||||
#define HAVE_STRING_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strndup' function. */
|
|
||||||
#define HAVE_STRNDUP 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the `strstr' function. */
|
|
||||||
#define HAVE_STRSTR 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
|
||||||
#define HAVE_SYS_STAT_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
|
||||||
#define HAVE_SYS_TIME_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
|
||||||
#define HAVE_SYS_TYPES_H 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
|
||||||
#define HAVE_UNISTD_H 1
|
|
||||||
|
|
||||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
|
||||||
*/
|
|
||||||
#define LT_OBJDIR ".libs/"
|
|
||||||
|
|
||||||
/* Name of package */
|
|
||||||
#define PACKAGE "r3"
|
|
||||||
|
|
||||||
/* Define to the address where bug reports for this package should be sent. */
|
|
||||||
#define PACKAGE_BUGREPORT ""
|
|
||||||
|
|
||||||
/* Define to the full name of this package. */
|
|
||||||
#define PACKAGE_NAME "r3"
|
|
||||||
|
|
||||||
/* Define to the full name and version of this package. */
|
|
||||||
#define PACKAGE_STRING "r3 1.0.0"
|
|
||||||
|
|
||||||
/* Define to the one symbol short name of this package. */
|
|
||||||
#define PACKAGE_TARNAME "r3"
|
|
||||||
|
|
||||||
/* Define to the home page for this package. */
|
|
||||||
#define PACKAGE_URL ""
|
|
||||||
|
|
||||||
/* Define to the version of this package. */
|
|
||||||
#define PACKAGE_VERSION "1.0.0"
|
|
||||||
|
|
||||||
/* Define to 1 if you have the ANSI C header files. */
|
|
||||||
#define STDC_HEADERS 1
|
|
||||||
|
|
||||||
/* Define to 1 if you have the PATH_MAX macro. */
|
|
||||||
/* #undef USE_JEMALLOC */
|
|
||||||
|
|
||||||
/* Version number of package */
|
|
||||||
#define VERSION "1.0.0"
|
|
||||||
|
|
||||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
|
||||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
|
||||||
#ifndef __cplusplus
|
|
||||||
/* #undef inline */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Define to rpl_malloc if the replacement function should be used. */
|
|
||||||
/* #undef malloc */
|
|
||||||
|
|
||||||
/* Define to rpl_realloc if the replacement function should be used. */
|
|
||||||
/* #undef realloc */
|
|
||||||
|
|
||||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
|
||||||
/* #undef size_t */
|
|
29
include/r3.h
29
include/r3.h
|
@ -53,10 +53,8 @@ struct _node {
|
||||||
/** compile-time variables here.... **/
|
/** compile-time variables here.... **/
|
||||||
|
|
||||||
/* the combined regexp pattern string from pattern_tokens */
|
/* the combined regexp pattern string from pattern_tokens */
|
||||||
|
int compare_type;
|
||||||
char * combined_pattern;
|
char * combined_pattern;
|
||||||
int combined_pattern_len;
|
|
||||||
int ov_cnt;
|
|
||||||
int * ov;
|
|
||||||
pcre * pcre_pattern;
|
pcre * pcre_pattern;
|
||||||
pcre_extra * pcre_extra;
|
pcre_extra * pcre_extra;
|
||||||
|
|
||||||
|
@ -76,9 +74,9 @@ struct _edge {
|
||||||
|
|
||||||
char * pattern;
|
char * pattern;
|
||||||
int pattern_len;
|
int pattern_len;
|
||||||
|
int opcode;
|
||||||
float score;
|
float score;
|
||||||
bool has_slug:1;
|
bool has_slug:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -120,7 +118,9 @@ void r3_tree_free(node * tree);
|
||||||
|
|
||||||
void r3_edge_free(edge * edge);
|
void r3_edge_free(edge * edge);
|
||||||
|
|
||||||
edge * r3_node_add_child(node * n, char * pat , node *child);
|
edge * r3_node_connectl(node * n, char * pat, int len, int strdup, node *child);
|
||||||
|
|
||||||
|
#define r3_node_connect(n, pat, child) r3_node_connectl(n, pat, strlen(pat), 0, child)
|
||||||
|
|
||||||
edge * r3_node_find_edge(node * n, char * pat);
|
edge * r3_node_find_edge(node * n, char * pat);
|
||||||
|
|
||||||
|
@ -190,7 +190,18 @@ void r3_tree_feedback(node *tree, node *end);
|
||||||
|
|
||||||
#define METHOD_GET 2
|
#define METHOD_GET 2
|
||||||
#define METHOD_POST 2<<1
|
#define METHOD_POST 2<<1
|
||||||
#define METHOD_PUT 2<<1
|
#define METHOD_PUT 2<<2
|
||||||
#define METHOD_DELETE 2<<1
|
#define METHOD_DELETE 2<<3
|
||||||
|
#define METHOD_PATCH 2<<4
|
||||||
|
#define METHOD_HEAD 2<<5
|
||||||
|
#define METHOD_OPTIONS 2<<6
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int r3_pattern_to_opcode(char * pattern, int pattern_len);
|
||||||
|
|
||||||
|
enum { NODE_COMPARE_STR, NODE_COMPARE_PCRE, NODE_COMPARE_OPCODE };
|
||||||
|
|
||||||
|
enum { OP_EXPECT_MORE_DIGITS = 1, OP_EXPECT_MORE_WORDS, OP_EXPECT_NOSLASH, OP_EXPECT_NODASH, OP_EXPECT_MORE_ALPHA };
|
||||||
|
|
||||||
#endif /* !R3_NODE_H */
|
#endif /* !R3_NODE_H */
|
||||||
|
|
|
@ -16,9 +16,9 @@ char * slug_compile(char * str, int len);
|
||||||
|
|
||||||
bool contains_slug(char * str);
|
bool contains_slug(char * str);
|
||||||
|
|
||||||
char * find_slug_pattern(char *s1, int *len);
|
char * slug_find_pattern(char *s1, int *len);
|
||||||
|
|
||||||
char * find_slug_placeholder(char *s1, int *len);
|
char * slug_find_placeholder(char *s1, int *len);
|
||||||
|
|
||||||
char * inside_slug(char * needle, int needle_len, char *offset);
|
char * inside_slug(char * needle, int needle_len, char *offset);
|
||||||
|
|
||||||
|
|
527
install-sh
527
install-sh
|
@ -1,527 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
# install - install a program, script, or datafile
|
|
||||||
|
|
||||||
scriptversion=2011-11-20.07; # UTC
|
|
||||||
|
|
||||||
# This originates from X11R5 (mit/util/scripts/install.sh), which was
|
|
||||||
# later released in X11R6 (xc/config/util/install.sh) with the
|
|
||||||
# following copyright and license.
|
|
||||||
#
|
|
||||||
# Copyright (C) 1994 X Consortium
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
||||||
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
|
|
||||||
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
#
|
|
||||||
# Except as contained in this notice, the name of the X Consortium shall not
|
|
||||||
# be used in advertising or otherwise to promote the sale, use or other deal-
|
|
||||||
# ings in this Software without prior written authorization from the X Consor-
|
|
||||||
# tium.
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# FSF changes to this file are in the public domain.
|
|
||||||
#
|
|
||||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
|
||||||
# 'make' implicit rules from creating a file called install from it
|
|
||||||
# when there is no Makefile.
|
|
||||||
#
|
|
||||||
# This script is compatible with the BSD install script, but was written
|
|
||||||
# from scratch.
|
|
||||||
|
|
||||||
nl='
|
|
||||||
'
|
|
||||||
IFS=" "" $nl"
|
|
||||||
|
|
||||||
# set DOITPROG to echo to test this script
|
|
||||||
|
|
||||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
|
||||||
doit=${DOITPROG-}
|
|
||||||
if test -z "$doit"; then
|
|
||||||
doit_exec=exec
|
|
||||||
else
|
|
||||||
doit_exec=$doit
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Put in absolute file names if you don't have them in your path;
|
|
||||||
# or use environment vars.
|
|
||||||
|
|
||||||
chgrpprog=${CHGRPPROG-chgrp}
|
|
||||||
chmodprog=${CHMODPROG-chmod}
|
|
||||||
chownprog=${CHOWNPROG-chown}
|
|
||||||
cmpprog=${CMPPROG-cmp}
|
|
||||||
cpprog=${CPPROG-cp}
|
|
||||||
mkdirprog=${MKDIRPROG-mkdir}
|
|
||||||
mvprog=${MVPROG-mv}
|
|
||||||
rmprog=${RMPROG-rm}
|
|
||||||
stripprog=${STRIPPROG-strip}
|
|
||||||
|
|
||||||
posix_glob='?'
|
|
||||||
initialize_posix_glob='
|
|
||||||
test "$posix_glob" != "?" || {
|
|
||||||
if (set -f) 2>/dev/null; then
|
|
||||||
posix_glob=
|
|
||||||
else
|
|
||||||
posix_glob=:
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
'
|
|
||||||
|
|
||||||
posix_mkdir=
|
|
||||||
|
|
||||||
# Desired mode of installed file.
|
|
||||||
mode=0755
|
|
||||||
|
|
||||||
chgrpcmd=
|
|
||||||
chmodcmd=$chmodprog
|
|
||||||
chowncmd=
|
|
||||||
mvcmd=$mvprog
|
|
||||||
rmcmd="$rmprog -f"
|
|
||||||
stripcmd=
|
|
||||||
|
|
||||||
src=
|
|
||||||
dst=
|
|
||||||
dir_arg=
|
|
||||||
dst_arg=
|
|
||||||
|
|
||||||
copy_on_change=false
|
|
||||||
no_target_directory=
|
|
||||||
|
|
||||||
usage="\
|
|
||||||
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
|
|
||||||
or: $0 [OPTION]... SRCFILES... DIRECTORY
|
|
||||||
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
|
|
||||||
or: $0 [OPTION]... -d DIRECTORIES...
|
|
||||||
|
|
||||||
In the 1st form, copy SRCFILE to DSTFILE.
|
|
||||||
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
|
|
||||||
In the 4th, create DIRECTORIES.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--help display this help and exit.
|
|
||||||
--version display version info and exit.
|
|
||||||
|
|
||||||
-c (ignored)
|
|
||||||
-C install only if different (preserve the last data modification time)
|
|
||||||
-d create directories instead of installing files.
|
|
||||||
-g GROUP $chgrpprog installed files to GROUP.
|
|
||||||
-m MODE $chmodprog installed files to MODE.
|
|
||||||
-o USER $chownprog installed files to USER.
|
|
||||||
-s $stripprog installed files.
|
|
||||||
-t DIRECTORY install into DIRECTORY.
|
|
||||||
-T report an error if DSTFILE is a directory.
|
|
||||||
|
|
||||||
Environment variables override the default commands:
|
|
||||||
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
|
|
||||||
RMPROG STRIPPROG
|
|
||||||
"
|
|
||||||
|
|
||||||
while test $# -ne 0; do
|
|
||||||
case $1 in
|
|
||||||
-c) ;;
|
|
||||||
|
|
||||||
-C) copy_on_change=true;;
|
|
||||||
|
|
||||||
-d) dir_arg=true;;
|
|
||||||
|
|
||||||
-g) chgrpcmd="$chgrpprog $2"
|
|
||||||
shift;;
|
|
||||||
|
|
||||||
--help) echo "$usage"; exit $?;;
|
|
||||||
|
|
||||||
-m) mode=$2
|
|
||||||
case $mode in
|
|
||||||
*' '* | *' '* | *'
|
|
||||||
'* | *'*'* | *'?'* | *'['*)
|
|
||||||
echo "$0: invalid mode: $mode" >&2
|
|
||||||
exit 1;;
|
|
||||||
esac
|
|
||||||
shift;;
|
|
||||||
|
|
||||||
-o) chowncmd="$chownprog $2"
|
|
||||||
shift;;
|
|
||||||
|
|
||||||
-s) stripcmd=$stripprog;;
|
|
||||||
|
|
||||||
-t) dst_arg=$2
|
|
||||||
# Protect names problematic for 'test' and other utilities.
|
|
||||||
case $dst_arg in
|
|
||||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
|
||||||
esac
|
|
||||||
shift;;
|
|
||||||
|
|
||||||
-T) no_target_directory=true;;
|
|
||||||
|
|
||||||
--version) echo "$0 $scriptversion"; exit $?;;
|
|
||||||
|
|
||||||
--) shift
|
|
||||||
break;;
|
|
||||||
|
|
||||||
-*) echo "$0: invalid option: $1" >&2
|
|
||||||
exit 1;;
|
|
||||||
|
|
||||||
*) break;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
|
|
||||||
# When -d is used, all remaining arguments are directories to create.
|
|
||||||
# When -t is used, the destination is already specified.
|
|
||||||
# Otherwise, the last argument is the destination. Remove it from $@.
|
|
||||||
for arg
|
|
||||||
do
|
|
||||||
if test -n "$dst_arg"; then
|
|
||||||
# $@ is not empty: it contains at least $arg.
|
|
||||||
set fnord "$@" "$dst_arg"
|
|
||||||
shift # fnord
|
|
||||||
fi
|
|
||||||
shift # arg
|
|
||||||
dst_arg=$arg
|
|
||||||
# Protect names problematic for 'test' and other utilities.
|
|
||||||
case $dst_arg in
|
|
||||||
-* | [=\(\)!]) dst_arg=./$dst_arg;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test $# -eq 0; then
|
|
||||||
if test -z "$dir_arg"; then
|
|
||||||
echo "$0: no input file specified." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# It's OK to call 'install-sh -d' without argument.
|
|
||||||
# This can happen when creating conditional directories.
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$dir_arg"; then
|
|
||||||
do_exit='(exit $ret); exit $ret'
|
|
||||||
trap "ret=129; $do_exit" 1
|
|
||||||
trap "ret=130; $do_exit" 2
|
|
||||||
trap "ret=141; $do_exit" 13
|
|
||||||
trap "ret=143; $do_exit" 15
|
|
||||||
|
|
||||||
# Set umask so as not to create temps with too-generous modes.
|
|
||||||
# However, 'strip' requires both read and write access to temps.
|
|
||||||
case $mode in
|
|
||||||
# Optimize common cases.
|
|
||||||
*644) cp_umask=133;;
|
|
||||||
*755) cp_umask=22;;
|
|
||||||
|
|
||||||
*[0-7])
|
|
||||||
if test -z "$stripcmd"; then
|
|
||||||
u_plus_rw=
|
|
||||||
else
|
|
||||||
u_plus_rw='% 200'
|
|
||||||
fi
|
|
||||||
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
|
|
||||||
*)
|
|
||||||
if test -z "$stripcmd"; then
|
|
||||||
u_plus_rw=
|
|
||||||
else
|
|
||||||
u_plus_rw=,u+rw
|
|
||||||
fi
|
|
||||||
cp_umask=$mode$u_plus_rw;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
for src
|
|
||||||
do
|
|
||||||
# Protect names problematic for 'test' and other utilities.
|
|
||||||
case $src in
|
|
||||||
-* | [=\(\)!]) src=./$src;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if test -n "$dir_arg"; then
|
|
||||||
dst=$src
|
|
||||||
dstdir=$dst
|
|
||||||
test -d "$dstdir"
|
|
||||||
dstdir_status=$?
|
|
||||||
else
|
|
||||||
|
|
||||||
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
|
|
||||||
# might cause directories to be created, which would be especially bad
|
|
||||||
# if $src (and thus $dsttmp) contains '*'.
|
|
||||||
if test ! -f "$src" && test ! -d "$src"; then
|
|
||||||
echo "$0: $src does not exist." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -z "$dst_arg"; then
|
|
||||||
echo "$0: no destination specified." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
dst=$dst_arg
|
|
||||||
|
|
||||||
# If destination is a directory, append the input filename; won't work
|
|
||||||
# if double slashes aren't ignored.
|
|
||||||
if test -d "$dst"; then
|
|
||||||
if test -n "$no_target_directory"; then
|
|
||||||
echo "$0: $dst_arg: Is a directory" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
dstdir=$dst
|
|
||||||
dst=$dstdir/`basename "$src"`
|
|
||||||
dstdir_status=0
|
|
||||||
else
|
|
||||||
# Prefer dirname, but fall back on a substitute if dirname fails.
|
|
||||||
dstdir=`
|
|
||||||
(dirname "$dst") 2>/dev/null ||
|
|
||||||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
|
||||||
X"$dst" : 'X\(//\)[^/]' \| \
|
|
||||||
X"$dst" : 'X\(//\)$' \| \
|
|
||||||
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
|
|
||||||
echo X"$dst" |
|
|
||||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
|
|
||||||
s//\1/
|
|
||||||
q
|
|
||||||
}
|
|
||||||
/^X\(\/\/\)[^/].*/{
|
|
||||||
s//\1/
|
|
||||||
q
|
|
||||||
}
|
|
||||||
/^X\(\/\/\)$/{
|
|
||||||
s//\1/
|
|
||||||
q
|
|
||||||
}
|
|
||||||
/^X\(\/\).*/{
|
|
||||||
s//\1/
|
|
||||||
q
|
|
||||||
}
|
|
||||||
s/.*/./; q'
|
|
||||||
`
|
|
||||||
|
|
||||||
test -d "$dstdir"
|
|
||||||
dstdir_status=$?
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
obsolete_mkdir_used=false
|
|
||||||
|
|
||||||
if test $dstdir_status != 0; then
|
|
||||||
case $posix_mkdir in
|
|
||||||
'')
|
|
||||||
# Create intermediate dirs using mode 755 as modified by the umask.
|
|
||||||
# This is like FreeBSD 'install' as of 1997-10-28.
|
|
||||||
umask=`umask`
|
|
||||||
case $stripcmd.$umask in
|
|
||||||
# Optimize common cases.
|
|
||||||
*[2367][2367]) mkdir_umask=$umask;;
|
|
||||||
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
|
|
||||||
|
|
||||||
*[0-7])
|
|
||||||
mkdir_umask=`expr $umask + 22 \
|
|
||||||
- $umask % 100 % 40 + $umask % 20 \
|
|
||||||
- $umask % 10 % 4 + $umask % 2
|
|
||||||
`;;
|
|
||||||
*) mkdir_umask=$umask,go-w;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# With -d, create the new directory with the user-specified mode.
|
|
||||||
# Otherwise, rely on $mkdir_umask.
|
|
||||||
if test -n "$dir_arg"; then
|
|
||||||
mkdir_mode=-m$mode
|
|
||||||
else
|
|
||||||
mkdir_mode=
|
|
||||||
fi
|
|
||||||
|
|
||||||
posix_mkdir=false
|
|
||||||
case $umask in
|
|
||||||
*[123567][0-7][0-7])
|
|
||||||
# POSIX mkdir -p sets u+wx bits regardless of umask, which
|
|
||||||
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
|
|
||||||
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
|
|
||||||
|
|
||||||
if (umask $mkdir_umask &&
|
|
||||||
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
if test -z "$dir_arg" || {
|
|
||||||
# Check for POSIX incompatibilities with -m.
|
|
||||||
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
|
|
||||||
# other-writable bit of parent directory when it shouldn't.
|
|
||||||
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
|
|
||||||
ls_ld_tmpdir=`ls -ld "$tmpdir"`
|
|
||||||
case $ls_ld_tmpdir in
|
|
||||||
d????-?r-*) different_mode=700;;
|
|
||||||
d????-?--*) different_mode=755;;
|
|
||||||
*) false;;
|
|
||||||
esac &&
|
|
||||||
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
|
|
||||||
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
|
|
||||||
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
then posix_mkdir=:
|
|
||||||
fi
|
|
||||||
rmdir "$tmpdir/d" "$tmpdir"
|
|
||||||
else
|
|
||||||
# Remove any dirs left behind by ancient mkdir implementations.
|
|
||||||
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
|
|
||||||
fi
|
|
||||||
trap '' 0;;
|
|
||||||
esac;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if
|
|
||||||
$posix_mkdir && (
|
|
||||||
umask $mkdir_umask &&
|
|
||||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
|
|
||||||
)
|
|
||||||
then :
|
|
||||||
else
|
|
||||||
|
|
||||||
# The umask is ridiculous, or mkdir does not conform to POSIX,
|
|
||||||
# or it failed possibly due to a race condition. Create the
|
|
||||||
# directory the slow way, step by step, checking for races as we go.
|
|
||||||
|
|
||||||
case $dstdir in
|
|
||||||
/*) prefix='/';;
|
|
||||||
[-=\(\)!]*) prefix='./';;
|
|
||||||
*) prefix='';;
|
|
||||||
esac
|
|
||||||
|
|
||||||
eval "$initialize_posix_glob"
|
|
||||||
|
|
||||||
oIFS=$IFS
|
|
||||||
IFS=/
|
|
||||||
$posix_glob set -f
|
|
||||||
set fnord $dstdir
|
|
||||||
shift
|
|
||||||
$posix_glob set +f
|
|
||||||
IFS=$oIFS
|
|
||||||
|
|
||||||
prefixes=
|
|
||||||
|
|
||||||
for d
|
|
||||||
do
|
|
||||||
test X"$d" = X && continue
|
|
||||||
|
|
||||||
prefix=$prefix$d
|
|
||||||
if test -d "$prefix"; then
|
|
||||||
prefixes=
|
|
||||||
else
|
|
||||||
if $posix_mkdir; then
|
|
||||||
(umask=$mkdir_umask &&
|
|
||||||
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
|
|
||||||
# Don't fail if two instances are running concurrently.
|
|
||||||
test -d "$prefix" || exit 1
|
|
||||||
else
|
|
||||||
case $prefix in
|
|
||||||
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
|
|
||||||
*) qprefix=$prefix;;
|
|
||||||
esac
|
|
||||||
prefixes="$prefixes '$qprefix'"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
prefix=$prefix/
|
|
||||||
done
|
|
||||||
|
|
||||||
if test -n "$prefixes"; then
|
|
||||||
# Don't fail if two instances are running concurrently.
|
|
||||||
(umask $mkdir_umask &&
|
|
||||||
eval "\$doit_exec \$mkdirprog $prefixes") ||
|
|
||||||
test -d "$dstdir" || exit 1
|
|
||||||
obsolete_mkdir_used=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test -n "$dir_arg"; then
|
|
||||||
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
|
|
||||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
|
|
||||||
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
|
|
||||||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
|
|
||||||
else
|
|
||||||
|
|
||||||
# Make a couple of temp file names in the proper directory.
|
|
||||||
dsttmp=$dstdir/_inst.$$_
|
|
||||||
rmtmp=$dstdir/_rm.$$_
|
|
||||||
|
|
||||||
# Trap to clean up those temp files at exit.
|
|
||||||
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
|
|
||||||
|
|
||||||
# Copy the file name to the temp name.
|
|
||||||
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
|
|
||||||
|
|
||||||
# and set any options; do chmod last to preserve setuid bits.
|
|
||||||
#
|
|
||||||
# If any of these fail, we abort the whole thing. If we want to
|
|
||||||
# ignore errors from any of these, just make sure not to ignore
|
|
||||||
# errors from the above "$doit $cpprog $src $dsttmp" command.
|
|
||||||
#
|
|
||||||
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
|
|
||||||
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
|
|
||||||
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
|
|
||||||
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
|
|
||||||
|
|
||||||
# If -C, don't bother to copy if it wouldn't change the file.
|
|
||||||
if $copy_on_change &&
|
|
||||||
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
|
|
||||||
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
|
|
||||||
|
|
||||||
eval "$initialize_posix_glob" &&
|
|
||||||
$posix_glob set -f &&
|
|
||||||
set X $old && old=:$2:$4:$5:$6 &&
|
|
||||||
set X $new && new=:$2:$4:$5:$6 &&
|
|
||||||
$posix_glob set +f &&
|
|
||||||
|
|
||||||
test "$old" = "$new" &&
|
|
||||||
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
rm -f "$dsttmp"
|
|
||||||
else
|
|
||||||
# Rename the file to the real destination.
|
|
||||||
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
|
|
||||||
|
|
||||||
# The rename failed, perhaps because mv can't rename something else
|
|
||||||
# to itself, or perhaps because mv is so ancient that it does not
|
|
||||||
# support -f.
|
|
||||||
{
|
|
||||||
# Now remove or move aside any old file at destination location.
|
|
||||||
# We try this two ways since rm can't unlink itself on some
|
|
||||||
# systems and the destination file might be busy for other
|
|
||||||
# reasons. In this case, the final cleanup might fail but the new
|
|
||||||
# file should still install successfully.
|
|
||||||
{
|
|
||||||
test ! -f "$dst" ||
|
|
||||||
$doit $rmcmd -f "$dst" 2>/dev/null ||
|
|
||||||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
|
|
||||||
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
|
|
||||||
} ||
|
|
||||||
{ echo "$0: cannot unlink or rename $dst" >&2
|
|
||||||
(exit 1); exit 1
|
|
||||||
}
|
|
||||||
} &&
|
|
||||||
|
|
||||||
# Now rename the file to the real destination.
|
|
||||||
$doit $mvcmd "$dsttmp" "$dst"
|
|
||||||
}
|
|
||||||
fi || exit 1
|
|
||||||
|
|
||||||
trap '' 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Local variables:
|
|
||||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
|
||||||
# time-stamp-start: "scriptversion="
|
|
||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
|
||||||
# time-stamp-time-zone: "UTC"
|
|
||||||
# time-stamp-end: "; # UTC"
|
|
||||||
# End:
|
|
|
@ -1,17 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
|
||||||
|
|
||||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
|
||||||
# install(TARGETS swiftnav-static DESTINATION lib${LIB_SUFFIX})
|
|
||||||
|
|
||||||
set(R3_SRCS node.c str.c list.c token.c edge.c zmalloc.c)
|
|
||||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -pipe -g3 -funroll-loops -O0")
|
|
||||||
|
|
||||||
# set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Judy_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
|
||||||
set(LIBS ${LIBS} ${PCRE_LIBRARIES} ${Jemalloc_LIBRARIES} r3)
|
|
||||||
|
|
||||||
# add_library(r3 SHARED ${R3_SRCS})
|
|
||||||
add_library(r3 STATIC ${R3_SRCS})
|
|
||||||
target_link_libraries(r3 ${LIBS})
|
|
||||||
install (TARGETS r3 DESTINATION lib)
|
|
||||||
# target_link_libraries(r3 cblas)
|
|
||||||
# install(FILES ${libswiftnav_HEADERS} DESTINATION include/libswiftnav)
|
|
|
@ -28,6 +28,7 @@ edge * r3_edge_create(char * pattern, int pattern_len, node * child) {
|
||||||
edge * e = (edge*) zmalloc( sizeof(edge) );
|
edge * e = (edge*) zmalloc( sizeof(edge) );
|
||||||
e->pattern = pattern;
|
e->pattern = pattern;
|
||||||
e->pattern_len = pattern_len;
|
e->pattern_len = pattern_len;
|
||||||
|
e->opcode = 0;
|
||||||
e->child = child;
|
e->child = child;
|
||||||
e->parent = NULL;
|
e->parent = NULL;
|
||||||
|
|
||||||
|
@ -81,17 +82,16 @@ node * r3_edge_branch(edge *e, int dl) {
|
||||||
e->child->data = NULL;
|
e->child->data = NULL;
|
||||||
|
|
||||||
// truncate the original edge pattern
|
// truncate the original edge pattern
|
||||||
char *op = e->pattern;
|
char *oldpattern = e->pattern;
|
||||||
e->pattern = zstrndup(e->pattern, dl);
|
e->pattern = zstrndup(e->pattern, dl);
|
||||||
e->pattern_len = dl;
|
e->pattern_len = dl;
|
||||||
|
zfree(oldpattern);
|
||||||
|
|
||||||
return new_child;
|
return new_child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3_edge_free(edge * e) {
|
void r3_edge_free(edge * e) {
|
||||||
if (e->pattern) {
|
zfree(e->pattern);
|
||||||
zfree(e->pattern);
|
|
||||||
}
|
|
||||||
if ( e->child ) {
|
if ( e->child ) {
|
||||||
r3_tree_free(e->child);
|
r3_tree_free(e->child);
|
||||||
}
|
}
|
||||||
|
|
230
src/node.c
230
src/node.c
|
@ -1,20 +1,14 @@
|
||||||
#include <config.h>
|
#include "config.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
// Jemalloc memory management
|
|
||||||
// #include <jemalloc/jemalloc.h>
|
|
||||||
|
|
||||||
// PCRE
|
// PCRE
|
||||||
#include <pcre.h>
|
#include <pcre.h>
|
||||||
|
|
||||||
// Judy array
|
|
||||||
// #include <Judy.h>
|
|
||||||
|
|
||||||
#include "r3.h"
|
#include "r3.h"
|
||||||
#include "r3_define.h"
|
|
||||||
#include "r3_str.h"
|
#include "r3_str.h"
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
@ -61,8 +55,6 @@ node * r3_tree_create(int cap) {
|
||||||
n->combined_pattern = NULL;
|
n->combined_pattern = NULL;
|
||||||
n->pcre_pattern = NULL;
|
n->pcre_pattern = NULL;
|
||||||
n->pcre_extra = NULL;
|
n->pcre_extra = NULL;
|
||||||
n->ov_cnt = 0;
|
|
||||||
n->ov = NULL;
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,12 +64,9 @@ void r3_tree_free(node * tree) {
|
||||||
r3_edge_free(tree->edges[ i ]);
|
r3_edge_free(tree->edges[ i ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tree->edges) {
|
zfree(tree->edges);
|
||||||
zfree(tree->edges);
|
zfree(tree->routes);
|
||||||
}
|
|
||||||
if (tree->routes) {
|
|
||||||
zfree(tree->routes);
|
|
||||||
}
|
|
||||||
if (tree->pcre_pattern) {
|
if (tree->pcre_pattern) {
|
||||||
pcre_free(tree->pcre_pattern);
|
pcre_free(tree->pcre_pattern);
|
||||||
}
|
}
|
||||||
|
@ -86,21 +75,13 @@ void r3_tree_free(node * tree) {
|
||||||
pcre_free_study(tree->pcre_extra);
|
pcre_free_study(tree->pcre_extra);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
zfree(tree->combined_pattern);
|
||||||
if (tree->combined_pattern)
|
|
||||||
zfree(tree->combined_pattern);
|
|
||||||
if (tree->ov)
|
|
||||||
zfree(tree->ov);
|
|
||||||
zfree(tree);
|
zfree(tree);
|
||||||
tree = NULL;
|
tree = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
edge * r3_node_connectl(node * n, char * pat, int len, int dupl, node *child) {
|
||||||
|
|
||||||
/* parent node, edge pattern, child */
|
|
||||||
edge * r3_node_add_child(node * n, char * pat , node *child) {
|
|
||||||
// find the same sub-pattern, if it does not exist, create one
|
// find the same sub-pattern, if it does not exist, create one
|
||||||
|
|
||||||
edge * e;
|
edge * e;
|
||||||
|
|
||||||
e = r3_node_find_edge(n, pat);
|
e = r3_node_find_edge(n, pat);
|
||||||
|
@ -108,10 +89,11 @@ edge * r3_node_add_child(node * n, char * pat , node *child) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = r3_edge_create( pat, strlen(pat), child);
|
if (dupl) {
|
||||||
|
pat = zstrndup(pat, len);
|
||||||
|
}
|
||||||
|
e = r3_edge_create(pat, len, child);
|
||||||
r3_node_append_edge(n, e);
|
r3_node_append_edge(n, e);
|
||||||
// str_array_append(n->edge_patterns, pat);
|
|
||||||
// assert( str_array_len(n->edge_patterns) == n->edge_len );
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,9 +179,15 @@ void r3_tree_compile_patterns(node * n) {
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
edge *e = NULL;
|
edge *e = NULL;
|
||||||
|
int opcode_cnt = 0;
|
||||||
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
for ( int i = 0 ; i < n->edge_len ; i++ ) {
|
||||||
e = n->edges[i];
|
e = n->edges[i];
|
||||||
|
|
||||||
|
if ( e->opcode )
|
||||||
|
opcode_cnt++;
|
||||||
|
|
||||||
if ( e->has_slug ) {
|
if ( e->has_slug ) {
|
||||||
|
// compile "foo/{slug}" to "foo/[^/]+"
|
||||||
char * slug_pat = slug_compile(e->pattern, e->pattern_len);
|
char * slug_pat = slug_compile(e->pattern, e->pattern_len);
|
||||||
strcat(p, slug_pat);
|
strcat(p, slug_pat);
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,13 +206,15 @@ void r3_tree_compile_patterns(node * n) {
|
||||||
|
|
||||||
info("pattern: %s\n",cpat);
|
info("pattern: %s\n",cpat);
|
||||||
|
|
||||||
n->ov_cnt = (1 + n->edge_len) * 3;
|
// if all edges use opcode, we should skip the combined_pattern.
|
||||||
n->ov = (int*) zcalloc(sizeof(int) * n->ov_cnt);
|
if ( opcode_cnt == n->edge_len ) {
|
||||||
|
// zfree(cpat);
|
||||||
|
n->compare_type = NODE_COMPARE_OPCODE;
|
||||||
|
} else {
|
||||||
|
n->compare_type = NODE_COMPARE_PCRE;
|
||||||
|
}
|
||||||
|
|
||||||
n->combined_pattern = cpat;
|
n->combined_pattern = cpat;
|
||||||
n->combined_pattern_len = p - cpat;
|
|
||||||
|
|
||||||
|
|
||||||
const char *error;
|
const char *error;
|
||||||
int erroffset;
|
int erroffset;
|
||||||
|
@ -290,47 +280,93 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
||||||
edge *e;
|
edge *e;
|
||||||
int rc;
|
int rc;
|
||||||
int i;
|
int i;
|
||||||
|
int ov_cnt;
|
||||||
|
int restlen;
|
||||||
|
char *pp;
|
||||||
|
char *pp_end = path + path_len;
|
||||||
|
|
||||||
|
if (n->compare_type == NODE_COMPARE_OPCODE) {
|
||||||
|
for (i = 0; i < n->edge_len ; i++ ) {
|
||||||
|
pp = path;
|
||||||
|
e = n->edges[i];
|
||||||
|
switch(e->opcode) {
|
||||||
|
case OP_EXPECT_NOSLASH:
|
||||||
|
while (*pp != '/' && pp < pp_end) pp++;
|
||||||
|
break;
|
||||||
|
case OP_EXPECT_MORE_ALPHA:
|
||||||
|
while ( isalpha(*pp) && pp < pp_end) pp++;
|
||||||
|
break;
|
||||||
|
case OP_EXPECT_MORE_DIGITS:
|
||||||
|
while ( isdigit(*pp) && pp < pp_end) pp++;
|
||||||
|
break;
|
||||||
|
case OP_EXPECT_MORE_WORDS:
|
||||||
|
while ( (isdigit(*pp) || isalpha(*pp)) && pp < pp_end) pp++;
|
||||||
|
break;
|
||||||
|
case OP_EXPECT_NODASH:
|
||||||
|
while (*pp != '-' && pp < pp_end) pp++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check match
|
||||||
|
if ( (pp - path) > 0) {
|
||||||
|
restlen = pp_end - pp;
|
||||||
|
if (entry) {
|
||||||
|
str_array_append(entry->vars , zstrndup(path, pp - path));
|
||||||
|
}
|
||||||
|
if (restlen == 0) {
|
||||||
|
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||||
|
}
|
||||||
|
return r3_tree_matchl(e->child, pp, pp_end - pp, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if the pcre_pattern is found, and the pointer is not NULL, then it's
|
// if the pcre_pattern is found, and the pointer is not NULL, then it's
|
||||||
// pcre pattern node, we use pcre_exec to match the nodes
|
// pcre pattern node, we use pcre_exec to match the nodes
|
||||||
if (n->pcre_pattern) {
|
if (n->pcre_pattern) {
|
||||||
info("pcre matching %s on %s\n", n->combined_pattern, path);
|
info("pcre matching %s on %s\n", n->combined_pattern, path);
|
||||||
|
ov_cnt = (1 + n->edge_len) * 3;
|
||||||
|
int ov[ ov_cnt ];
|
||||||
|
|
||||||
rc = pcre_exec(
|
rc = pcre_exec(
|
||||||
n->pcre_pattern, /* the compiled pattern */
|
n->pcre_pattern, /* the compiled pattern */
|
||||||
|
n->pcre_extra,
|
||||||
|
path, /* the subject string */
|
||||||
|
path_len, /* the length of the subject */
|
||||||
|
0, /* start at offset 0 in the subject */
|
||||||
|
0, /* default options */
|
||||||
|
ov, /* output vector for substring information */
|
||||||
|
ov_cnt); /* number of elements in the output vector */
|
||||||
|
|
||||||
// PCRE Study makes this slow
|
// does not match all edges, return NULL;
|
||||||
NULL, // n->pcre_extra, /* no extra data - we didn't study the pattern */
|
|
||||||
path, /* the subject string */
|
|
||||||
path_len, /* the length of the subject */
|
|
||||||
0, /* start at offset 0 in the subject */
|
|
||||||
0, /* default options */
|
|
||||||
n->ov, /* output vector for substring information */
|
|
||||||
n->ov_cnt); /* number of elements in the output vector */
|
|
||||||
|
|
||||||
// info("rc: %d\n", rc );
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf("pcre rc: %d\n", rc );
|
||||||
switch(rc)
|
switch(rc)
|
||||||
{
|
{
|
||||||
case PCRE_ERROR_NOMATCH: printf("pcre: no match\n"); break;
|
case PCRE_ERROR_NOMATCH:
|
||||||
/*
|
printf("pcre: no match '%s' on pattern '%s'\n", path, n->combined_pattern);
|
||||||
Handle other special cases if you like
|
break;
|
||||||
*/
|
|
||||||
default: printf("pcre matching error '%d' on pattern '%s'\n", rc, n->combined_pattern); break;
|
// Handle other special cases if you like
|
||||||
|
default:
|
||||||
|
printf("pcre matching error '%d' '%s' on pattern '%s'\n", rc, path, n->combined_pattern);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// does not match all edges, return NULL;
|
#endif
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *substring_start;
|
||||||
|
int substring_length;
|
||||||
for (i = 1; i < rc; i++)
|
for (i = 1; i < rc; i++)
|
||||||
{
|
{
|
||||||
char *substring_start = path + n->ov[2*i];
|
substring_start = path + ov[2*i];
|
||||||
int substring_length = n->ov[2*i+1] - n->ov[2*i];
|
substring_length = ov[2*i+1] - ov[2*i];
|
||||||
// info("%2d: %.*s\n", i, substring_length, substring_start);
|
// info("%2d: %.*s\n", i, substring_length, substring_start);
|
||||||
|
|
||||||
if ( substring_length > 0) {
|
if ( substring_length > 0) {
|
||||||
int restlen = path_len - n->ov[1]; // fully match to the end
|
restlen = path_len - ov[1]; // fully match to the end
|
||||||
// info("matched item => restlen:%d edges:%d i:%d\n", restlen, n->edge_len, i);
|
// info("matched item => restlen:%d edges:%d i:%d\n", restlen, n->edge_len, i);
|
||||||
|
|
||||||
e = n->edges[i - 1];
|
e = n->edges[i - 1];
|
||||||
|
@ -343,7 +379,7 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
||||||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||||
}
|
}
|
||||||
// get the length of orginal string: $0
|
// get the length of orginal string: $0
|
||||||
return r3_tree_matchl( e->child, path + (n->ov[1] - n->ov[0]), restlen, entry);
|
return r3_tree_matchl( e->child, path + (ov[1] - ov[0]), restlen, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// does not match
|
// does not match
|
||||||
|
@ -351,7 +387,7 @@ node * r3_tree_matchl(const node * n, char * path, int path_len, match_entry * e
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (e = r3_node_find_edge_str(n, path, path_len)) != NULL ) {
|
if ( (e = r3_node_find_edge_str(n, path, path_len)) != NULL ) {
|
||||||
int restlen = path_len - e->pattern_len;
|
restlen = path_len - e->pattern_len;
|
||||||
if (restlen == 0) {
|
if (restlen == 0) {
|
||||||
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
return e->child && e->child->endpoint > 0 ? e->child : NULL;
|
||||||
}
|
}
|
||||||
|
@ -376,24 +412,20 @@ route * r3_tree_match_route(const node *tree, match_entry * entry) {
|
||||||
|
|
||||||
inline edge * r3_node_find_edge_str(const node * n, char * str, int str_len) {
|
inline edge * r3_node_find_edge_str(const node * n, char * str, int str_len) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int matched_idx = 0;
|
int matched_idx = -1;
|
||||||
char firstbyte = *str;
|
char firstbyte = *str;
|
||||||
for (; i < n->edge_len ; i++ ) {
|
for (; i < n->edge_len ; i++ ) {
|
||||||
if ( firstbyte == *(n->edges[i]->pattern) ) {
|
if ( firstbyte == *(n->edges[i]->pattern) ) {
|
||||||
matched_idx = i;
|
info("matching '%s' with '%s'\n", str, node_edge_pattern(n,i) );
|
||||||
break;
|
if ( strncmp( node_edge_pattern(n,i), str, node_edge_pattern_len(n,i) ) == 0 ) {
|
||||||
|
return n->edges[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info("matching '%s' with '%s'\n", str, node_edge_pattern(n,i) );
|
|
||||||
if ( strncmp( node_edge_pattern(n,matched_idx), str, node_edge_pattern_len(n,matched_idx) ) == 0 ) {
|
|
||||||
return n->edges[matched_idx];
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
node * r3_node_create() {
|
node * r3_node_create() {
|
||||||
node * n = (node*) zmalloc( sizeof(node) );
|
node * n = (node*) zmalloc( sizeof(node) );
|
||||||
n->edges = NULL;
|
n->edges = NULL;
|
||||||
|
@ -474,17 +506,18 @@ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route
|
||||||
// common prefix not found, insert a new edge for this pattern
|
// common prefix not found, insert a new edge for this pattern
|
||||||
if ( prefix_len == 0 ) {
|
if ( prefix_len == 0 ) {
|
||||||
// there are two more slugs, we should break them into several parts
|
// there are two more slugs, we should break them into several parts
|
||||||
if ( slug_count(path, path_len) > 1 ) {
|
int slug_cnt = slug_count(path, path_len);
|
||||||
|
if ( slug_cnt > 1 ) {
|
||||||
int slug_len;
|
int slug_len;
|
||||||
char *p = find_slug_placeholder(path, &slug_len);
|
char *p = slug_find_placeholder(path, &slug_len);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
assert(p);
|
assert(p);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// find the next one
|
// find the next one '{', then break there
|
||||||
if(p) {
|
if(p) {
|
||||||
p = find_slug_placeholder(p + slug_len + 1, NULL);
|
p = slug_find_placeholder(p + slug_len + 1, NULL);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
assert(p);
|
assert(p);
|
||||||
|
@ -492,18 +525,62 @@ node * r3_tree_insert_pathl_(node *tree, char *path, int path_len, route * route
|
||||||
|
|
||||||
// insert the first one edge, and break at "p"
|
// insert the first one edge, and break at "p"
|
||||||
node * child = r3_tree_create(3);
|
node * child = r3_tree_create(3);
|
||||||
r3_node_add_child(n, zstrndup(path, (int)(p - path)), child);
|
r3_node_connect(n, zstrndup(path, (int)(p - path)), child);
|
||||||
child->endpoint = 0;
|
|
||||||
|
|
||||||
// and insert the rest part to the child
|
// and insert the rest part to the child
|
||||||
return r3_tree_insert_pathl_(child, p, path_len - (int)(p - path), route, data);
|
return r3_tree_insert_pathl_(child, p, path_len - (int)(p - path), route, data);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if (slug_cnt == 1) {
|
||||||
|
// there is one slug, let's see if it's optimiz-able by opcode
|
||||||
|
int slug_len = 0;
|
||||||
|
char *slug_p = slug_find_placeholder(path, &slug_len);
|
||||||
|
int slug_pattern_len = 0;
|
||||||
|
char *slug_pattern = slug_find_pattern(slug_p, &slug_pattern_len);
|
||||||
|
int opcode = 0;
|
||||||
|
// if there is a pattern defined.
|
||||||
|
if (slug_pattern) {
|
||||||
|
char *cpattern = slug_compile(slug_pattern, slug_pattern_len);
|
||||||
|
opcode = r3_pattern_to_opcode(cpattern, strlen(cpattern));
|
||||||
|
zfree(cpattern);
|
||||||
|
} else {
|
||||||
|
opcode = OP_EXPECT_NOSLASH;
|
||||||
|
}
|
||||||
|
// found opcode
|
||||||
|
if (opcode) {
|
||||||
|
// if the slug starts after one+ charactor, for example foo{slug}
|
||||||
|
node *c1;
|
||||||
|
if (slug_p > path) {
|
||||||
|
c1 = r3_tree_create(3);
|
||||||
|
r3_node_connectl(n, path, slug_p - path, 1, c1); // duplicate
|
||||||
|
} else {
|
||||||
|
c1 = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
node * c2 = r3_tree_create(3);
|
||||||
|
edge * op_edge = r3_node_connectl(c1, slug_p, slug_len , 1, c2);
|
||||||
|
op_edge->opcode = opcode;
|
||||||
|
|
||||||
|
// insert rest
|
||||||
|
int restlen = (path_len - (slug_p - path)) - slug_len;
|
||||||
|
if (restlen) {
|
||||||
|
return r3_tree_insert_pathl_(c2, slug_p + slug_len, restlen, route, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
c2->data = data;
|
||||||
|
c2->endpoint++;
|
||||||
|
if (route) {
|
||||||
|
route->data = data;
|
||||||
|
r3_node_append_route(c2, route);
|
||||||
|
}
|
||||||
|
return c2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// only one slug
|
||||||
node * child = r3_tree_create(3);
|
node * child = r3_tree_create(3);
|
||||||
r3_node_add_child(n, zstrndup(path, path_len) , child);
|
r3_node_connect(n, zstrndup(path, path_len) , child);
|
||||||
// info("edge not found, insert one: %s\n", path);
|
|
||||||
child->data = data;
|
child->data = data;
|
||||||
child->endpoint++;
|
child->endpoint++;
|
||||||
|
|
||||||
if (route) {
|
if (route) {
|
||||||
route->data = data;
|
route->data = data;
|
||||||
r3_node_append_route(child, route);
|
r3_node_append_route(child, route);
|
||||||
|
@ -587,6 +664,9 @@ void r3_tree_dump(node * n, int level) {
|
||||||
|
|
||||||
// printf(" hits:%lld score:%.1f ", e->hits, e->score);
|
// printf(" hits:%lld score:%.1f ", e->hits, e->score);
|
||||||
printf(" score:%.1f ", e->score);
|
printf(" score:%.1f ", e->score);
|
||||||
|
if (e->opcode ) {
|
||||||
|
printf(" opcode:%d", e->opcode);
|
||||||
|
}
|
||||||
|
|
||||||
if ( e->child ) {
|
if ( e->child ) {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
35
src/str.c
35
src/str.c
|
@ -13,6 +13,33 @@
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
|
int r3_pattern_to_opcode(char * pattern, int len) {
|
||||||
|
if ( strncmp(pattern, "\\w+",len) == 0 ) {
|
||||||
|
return OP_EXPECT_MORE_WORDS;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "[0-9a-z]+",len) == 0 || strncmp(pattern, "[a-z0-9]+",len) == 0 ) {
|
||||||
|
return OP_EXPECT_MORE_WORDS;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "[a-z]+",len) == 0 ) {
|
||||||
|
return OP_EXPECT_MORE_ALPHA;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "\\d+", len) == 0 ) {
|
||||||
|
return OP_EXPECT_MORE_DIGITS;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "[0-9]+", len) == 0 ) {
|
||||||
|
return OP_EXPECT_MORE_DIGITS;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "[^/]+", len) == 0 ) {
|
||||||
|
return OP_EXPECT_NOSLASH;
|
||||||
|
}
|
||||||
|
if ( strncmp(pattern, "[^-]+", len) == 0 ) {
|
||||||
|
return OP_EXPECT_NODASH;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide a quick way to count slugs, simply search for '{'
|
* provide a quick way to count slugs, simply search for '{'
|
||||||
*/
|
*/
|
||||||
|
@ -66,7 +93,7 @@ char * inside_slug(char * needle, int needle_len, char *offset) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * find_slug_placeholder(char *s1, int *len) {
|
char * slug_find_placeholder(char *s1, int *len) {
|
||||||
char *c;
|
char *c;
|
||||||
char *s2;
|
char *s2;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
|
@ -98,7 +125,7 @@ char * find_slug_placeholder(char *s1, int *len) {
|
||||||
/**
|
/**
|
||||||
* given a slug string, duplicate the pattern string of the slug
|
* given a slug string, duplicate the pattern string of the slug
|
||||||
*/
|
*/
|
||||||
char * find_slug_pattern(char *s1, int *len) {
|
char * slug_find_pattern(char *s1, int *len) {
|
||||||
char *c;
|
char *c;
|
||||||
char *s2;
|
char *s2;
|
||||||
int cnt = 1;
|
int cnt = 1;
|
||||||
|
@ -136,7 +163,7 @@ char * slug_compile(char * str, int len)
|
||||||
|
|
||||||
// append prefix
|
// append prefix
|
||||||
int s1_len;
|
int s1_len;
|
||||||
s1 = find_slug_placeholder(str, &s1_len);
|
s1 = slug_find_placeholder(str, &s1_len);
|
||||||
|
|
||||||
if ( s1 == NULL ) {
|
if ( s1 == NULL ) {
|
||||||
return zstrdup(str);
|
return zstrdup(str);
|
||||||
|
@ -153,7 +180,7 @@ char * slug_compile(char * str, int len)
|
||||||
|
|
||||||
|
|
||||||
int pat_len;
|
int pat_len;
|
||||||
pat = find_slug_pattern(s1, &pat_len);
|
pat = slug_find_pattern(s1, &pat_len);
|
||||||
|
|
||||||
if (pat) {
|
if (pat) {
|
||||||
*o = '(';
|
*o = '(';
|
||||||
|
|
139
test-driver
139
test-driver
|
@ -1,139 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
# test-driver - basic testsuite driver script.
|
|
||||||
|
|
||||||
scriptversion=2013-07-13.22; # UTC
|
|
||||||
|
|
||||||
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2, 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 General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
# As a special exception to the GNU General Public License, if you
|
|
||||||
# distribute this file as part of a program that contains a
|
|
||||||
# configuration script generated by Autoconf, you may include it under
|
|
||||||
# the same distribution terms that you use for the rest of that program.
|
|
||||||
|
|
||||||
# This file is maintained in Automake, please report
|
|
||||||
# bugs to <bug-automake@gnu.org> or send patches to
|
|
||||||
# <automake-patches@gnu.org>.
|
|
||||||
|
|
||||||
# Make unconditional expansion of undefined variables an error. This
|
|
||||||
# helps a lot in preventing typo-related bugs.
|
|
||||||
set -u
|
|
||||||
|
|
||||||
usage_error ()
|
|
||||||
{
|
|
||||||
echo "$0: $*" >&2
|
|
||||||
print_usage >&2
|
|
||||||
exit 2
|
|
||||||
}
|
|
||||||
|
|
||||||
print_usage ()
|
|
||||||
{
|
|
||||||
cat <<END
|
|
||||||
Usage:
|
|
||||||
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
|
|
||||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
|
||||||
[--enable-hard-errors={yes|no}] [--]
|
|
||||||
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
|
|
||||||
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
|
|
||||||
END
|
|
||||||
}
|
|
||||||
|
|
||||||
test_name= # Used for reporting.
|
|
||||||
log_file= # Where to save the output of the test script.
|
|
||||||
trs_file= # Where to save the metadata of the test run.
|
|
||||||
expect_failure=no
|
|
||||||
color_tests=no
|
|
||||||
enable_hard_errors=yes
|
|
||||||
while test $# -gt 0; do
|
|
||||||
case $1 in
|
|
||||||
--help) print_usage; exit $?;;
|
|
||||||
--version) echo "test-driver $scriptversion"; exit $?;;
|
|
||||||
--test-name) test_name=$2; shift;;
|
|
||||||
--log-file) log_file=$2; shift;;
|
|
||||||
--trs-file) trs_file=$2; shift;;
|
|
||||||
--color-tests) color_tests=$2; shift;;
|
|
||||||
--expect-failure) expect_failure=$2; shift;;
|
|
||||||
--enable-hard-errors) enable_hard_errors=$2; shift;;
|
|
||||||
--) shift; break;;
|
|
||||||
-*) usage_error "invalid option: '$1'";;
|
|
||||||
*) break;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
missing_opts=
|
|
||||||
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
|
|
||||||
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
|
|
||||||
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
|
|
||||||
if test x"$missing_opts" != x; then
|
|
||||||
usage_error "the following mandatory options are missing:$missing_opts"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test $# -eq 0; then
|
|
||||||
usage_error "missing argument"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if test $color_tests = yes; then
|
|
||||||
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
|
|
||||||
red='[0;31m' # Red.
|
|
||||||
grn='[0;32m' # Green.
|
|
||||||
lgn='[1;32m' # Light green.
|
|
||||||
blu='[1;34m' # Blue.
|
|
||||||
mgn='[0;35m' # Magenta.
|
|
||||||
std='[m' # No color.
|
|
||||||
else
|
|
||||||
red= grn= lgn= blu= mgn= std=
|
|
||||||
fi
|
|
||||||
|
|
||||||
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
|
|
||||||
trap "st=129; $do_exit" 1
|
|
||||||
trap "st=130; $do_exit" 2
|
|
||||||
trap "st=141; $do_exit" 13
|
|
||||||
trap "st=143; $do_exit" 15
|
|
||||||
|
|
||||||
# Test script is run here.
|
|
||||||
"$@" >$log_file 2>&1
|
|
||||||
estatus=$?
|
|
||||||
if test $enable_hard_errors = no && test $estatus -eq 99; then
|
|
||||||
estatus=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case $estatus:$expect_failure in
|
|
||||||
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
|
|
||||||
0:*) col=$grn res=PASS recheck=no gcopy=no;;
|
|
||||||
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
|
|
||||||
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
|
|
||||||
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
|
|
||||||
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Report outcome to console.
|
|
||||||
echo "${col}${res}${std}: $test_name"
|
|
||||||
|
|
||||||
# Register the test result, and other relevant metadata.
|
|
||||||
echo ":test-result: $res" > $trs_file
|
|
||||||
echo ":global-test-result: $res" >> $trs_file
|
|
||||||
echo ":recheck: $recheck" >> $trs_file
|
|
||||||
echo ":copy-in-global-log: $gcopy" >> $trs_file
|
|
||||||
|
|
||||||
# Local Variables:
|
|
||||||
# mode: shell-script
|
|
||||||
# sh-indentation: 2
|
|
||||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
|
||||||
# time-stamp-start: "scriptversion="
|
|
||||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
|
||||||
# time-stamp-time-zone: "UTC"
|
|
||||||
# time-stamp-end: "; # UTC"
|
|
||||||
# End:
|
|
|
@ -1,24 +0,0 @@
|
||||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
|
||||||
# set(TEST_LIBS ${TEST_LIBS} ${CHECK_LIBRARIES} judy libr3)
|
|
||||||
find_package(Check REQUIRED)
|
|
||||||
find_package(PCRE REQUIRED)
|
|
||||||
# find_package(Judy REQUIRED)
|
|
||||||
|
|
||||||
if (NOT CHECK_FOUND)
|
|
||||||
message(STATUS "Skipping unit tests, Check library not found!")
|
|
||||||
else (NOT CHECK_FOUND)
|
|
||||||
set(TEST_LIBS ${LIBS} ${CHECK_LIBRARIES} ${PCRE_LIBRARIES} r3)
|
|
||||||
|
|
||||||
include_directories(${CHECK_INCLUDE_DIRS})
|
|
||||||
# include_directories("${PROJECT_SOURCE_DIR}/include/r2")
|
|
||||||
add_executable(test_r3 test_tree.c)
|
|
||||||
target_link_libraries(test_r3 ${TEST_LIBS})
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
TARGET test_r3 POST_BUILD
|
|
||||||
COMMENT "Running unit tests"
|
|
||||||
COMMAND test_r3
|
|
||||||
)
|
|
||||||
endif (NOT CHECK_FOUND)
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ noinst_HEADERS = \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
dist_noinst_DATA = \
|
dist_noinst_DATA = \
|
||||||
bench_str.csv \
|
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
if USE_JEMALLOC
|
if USE_JEMALLOC
|
||||||
|
|
|
@ -450,10 +450,18 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
||||||
assert( *((int*) m->data) == 999 );
|
assert( *((int*) m->data) == 999 );
|
||||||
|
|
||||||
|
|
||||||
BENCHMARK(string_dispatch)
|
|
||||||
|
BENCHMARK(str_dispatch)
|
||||||
r3_tree_matchl(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
|
r3_tree_matchl(n , "/qux/bar/corge", strlen("/qux/bar/corge"), NULL);
|
||||||
END_BENCHMARK(string_dispatch)
|
END_BENCHMARK(str_dispatch)
|
||||||
BENCHMARK_SUMMARY(string_dispatch);
|
BENCHMARK_SUMMARY(str_dispatch);
|
||||||
|
|
||||||
|
BENCHMARK(str_match_entry)
|
||||||
|
match_entry * e = match_entry_createl("/qux/bar/corge", strlen("/qux/bar/corge") );
|
||||||
|
r3_tree_match_entry(n , e);
|
||||||
|
zfree(e);
|
||||||
|
END_BENCHMARK(str_match_entry)
|
||||||
|
BENCHMARK_SUMMARY(str_match_entry);
|
||||||
|
|
||||||
|
|
||||||
node * tree2 = r3_tree_create(1);
|
node * tree2 = r3_tree_create(1);
|
||||||
|
@ -465,6 +473,6 @@ r3_tree_insert_path(n, "/garply/grault/corge", NULL);
|
||||||
END_BENCHMARK(pcre_dispatch)
|
END_BENCHMARK(pcre_dispatch)
|
||||||
BENCHMARK_SUMMARY(pcre_dispatch);
|
BENCHMARK_SUMMARY(pcre_dispatch);
|
||||||
|
|
||||||
BENCHMARK_RECORD_CSV("bench_str.csv", 3, BR(string_dispatch), BR(pcre_dispatch), BR(tree_compile) );
|
BENCHMARK_RECORD_CSV("bench_str.csv", 4, BR(str_dispatch), BR(pcre_dispatch), BR(tree_compile), BR(str_match_entry) );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,23 +65,4 @@ void bench_append_csv(char *filename, int countOfB, ...);
|
||||||
|
|
||||||
#define BR(b) &b
|
#define BR(b) &b
|
||||||
|
|
||||||
|
|
||||||
#define BENCHMARK(B) \
|
|
||||||
bench B; B.N = 5000000; B.R = 3; \
|
|
||||||
bench_start(&B); \
|
|
||||||
for (int _r = 0; _r < B.R ; _r++ ) { \
|
|
||||||
for (int _i = 0; _i < B.N ; _i++ ) {
|
|
||||||
|
|
||||||
#define END_BENCHMARK(B) \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
bench_stop(&B);
|
|
||||||
|
|
||||||
#define BENCHMARK_SUMMARY(B) bench_print_summary(&B);
|
|
||||||
|
|
||||||
#define BENCHMARK_RECORD_CSV(B,filename) \
|
|
||||||
FILE *fp = fopen(filename, "a+"); \
|
|
||||||
fprintf(fp, "%ld,%.2f\n", unixtime(), (B.N * B.R) / (B.end - B.start)); \
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
#endif /* !BENCH_H */
|
#endif /* !BENCH_H */
|
||||||
|
|
|
@ -13,6 +13,15 @@
|
||||||
#include "str_array.h"
|
#include "str_array.h"
|
||||||
#include "zmalloc.h"
|
#include "zmalloc.h"
|
||||||
|
|
||||||
|
START_TEST (test_pattern_to_opcode)
|
||||||
|
{
|
||||||
|
ck_assert( r3_pattern_to_opcode("\\w+", strlen("\\w+")) == OP_EXPECT_MORE_WORDS );
|
||||||
|
ck_assert( r3_pattern_to_opcode("\\d+", strlen("\\d+")) == OP_EXPECT_MORE_DIGITS );
|
||||||
|
ck_assert( r3_pattern_to_opcode("[^/]+",strlen("[^/]+")) == OP_EXPECT_NOSLASH );
|
||||||
|
ck_assert( r3_pattern_to_opcode("[^-]+",strlen("[^-]+")) == OP_EXPECT_NODASH );
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_slug_compile)
|
START_TEST (test_slug_compile)
|
||||||
{
|
{
|
||||||
char * path = "/user/{id}";
|
char * path = "/user/{id}";
|
||||||
|
@ -41,24 +50,24 @@ START_TEST (test_contains_slug)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_slug_pattern)
|
START_TEST (test_slug_find_pattern)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
char * namerex = find_slug_pattern("{name:\\s+}", &len);
|
char * namerex = slug_find_pattern("{name:\\s+}", &len);
|
||||||
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
|
ck_assert( strncmp(namerex, "\\s+", len) == 0 );
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
START_TEST (test_find_slug_placeholder)
|
START_TEST (test_slug_find_placeholder)
|
||||||
{
|
{
|
||||||
int slug_len = 0;
|
int slug_len = 0;
|
||||||
char * slug;
|
char * slug;
|
||||||
slug = find_slug_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
|
slug = slug_find_placeholder("/user/{name:\\s+}/to/{id}", &slug_len);
|
||||||
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
|
ck_assert( strncmp(slug, "{name:\\s+}", slug_len) == 0 );
|
||||||
|
|
||||||
|
|
||||||
slug = find_slug_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
|
slug = slug_find_placeholder("/user/{idx:\\d{3}}/to/{idy:\\d{3}}", &slug_len);
|
||||||
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
|
ck_assert( slug_len == strlen("{idx:\\d{3}}") );
|
||||||
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
|
ck_assert( strncmp(slug, "{idx:\\d{3}}", slug_len) == 0 );
|
||||||
}
|
}
|
||||||
|
@ -86,10 +95,10 @@ START_TEST (test_slug_count)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
START_TEST (test_find_slug_placeholder_with_broken_slug)
|
START_TEST (test_slug_find_placeholder_with_broken_slug)
|
||||||
{
|
{
|
||||||
int slug_len = 0;
|
int slug_len = 0;
|
||||||
char * slug = find_slug_placeholder("/user/{name:\\s+/to/{id", &slug_len);
|
char * slug = slug_find_placeholder("/user/{name:\\s+/to/{id", &slug_len);
|
||||||
ck_assert(! slug);
|
ck_assert(! slug);
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
@ -101,11 +110,12 @@ Suite* r3_suite (void) {
|
||||||
tcase_set_timeout(tcase, 30);
|
tcase_set_timeout(tcase, 30);
|
||||||
tcase_add_test(tcase, test_contains_slug);
|
tcase_add_test(tcase, test_contains_slug);
|
||||||
tcase_add_test(tcase, test_inside_slug);
|
tcase_add_test(tcase, test_inside_slug);
|
||||||
tcase_add_test(tcase, test_find_slug_pattern);
|
tcase_add_test(tcase, test_slug_find_pattern);
|
||||||
tcase_add_test(tcase, test_find_slug_placeholder);
|
tcase_add_test(tcase, test_slug_find_placeholder);
|
||||||
tcase_add_test(tcase, test_find_slug_placeholder_with_broken_slug);
|
tcase_add_test(tcase, test_slug_find_placeholder_with_broken_slug);
|
||||||
tcase_add_test(tcase, test_slug_count);
|
tcase_add_test(tcase, test_slug_count);
|
||||||
tcase_add_test(tcase, test_slug_compile);
|
tcase_add_test(tcase, test_slug_compile);
|
||||||
|
tcase_add_test(tcase, test_pattern_to_opcode);
|
||||||
|
|
||||||
suite_add_tcase(suite, tcase);
|
suite_add_tcase(suite, tcase);
|
||||||
return suite;
|
return suite;
|
||||||
|
|
|
@ -32,7 +32,7 @@ START_TEST (test_r3_node_find_edge)
|
||||||
|
|
||||||
node * child = r3_tree_create(3);
|
node * child = r3_tree_create(3);
|
||||||
|
|
||||||
fail_if( r3_node_add_child(n, zstrdup("/add") , child) == FALSE );
|
fail_if( r3_node_connect(n, zstrdup("/add") , child) == FALSE );
|
||||||
|
|
||||||
fail_if( r3_node_find_edge(n, "/add") == NULL );
|
fail_if( r3_node_find_edge(n, "/add") == NULL );
|
||||||
fail_if( r3_node_find_edge(n, "/bar") != NULL );
|
fail_if( r3_node_find_edge(n, "/bar") != NULL );
|
||||||
|
@ -42,22 +42,25 @@ START_TEST (test_r3_node_find_edge)
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
START_TEST (test_compile)
|
static node * create_simple_str_tree() {
|
||||||
{
|
|
||||||
str_array *t;
|
|
||||||
node * n;
|
node * n;
|
||||||
n = r3_tree_create(10);
|
n = r3_tree_create(10);
|
||||||
|
|
||||||
|
|
||||||
node *m;
|
|
||||||
edge *e ;
|
|
||||||
|
|
||||||
r3_tree_insert_path(n, "/zoo", NULL);
|
r3_tree_insert_path(n, "/zoo", NULL);
|
||||||
r3_tree_insert_path(n, "/foo", NULL);
|
r3_tree_insert_path(n, "/foo", NULL);
|
||||||
r3_tree_insert_path(n, "/bar", NULL);
|
r3_tree_insert_path(n, "/bar", NULL);
|
||||||
r3_tree_compile(n);
|
r3_tree_compile(n);
|
||||||
fail_if( n->combined_pattern );
|
return n;
|
||||||
fail_if( NULL == r3_node_find_edge_str(n, "/", strlen("/") ) );
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_compile)
|
||||||
|
{
|
||||||
|
str_array *t;
|
||||||
|
node * n = create_simple_str_tree();
|
||||||
|
|
||||||
|
node *m;
|
||||||
|
edge *e ;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
r3_tree_dump(n, 0);
|
r3_tree_dump(n, 0);
|
||||||
|
@ -165,7 +168,6 @@ START_TEST (test_pcre_patterns_insert_3)
|
||||||
matched = r3_tree_match(n, "/post/11", NULL);
|
matched = r3_tree_match(n, "/post/11", NULL);
|
||||||
ck_assert(!matched);
|
ck_assert(!matched);
|
||||||
|
|
||||||
|
|
||||||
matched = r3_tree_match(n, "/post/11/", NULL);
|
matched = r3_tree_match(n, "/post/11/", NULL);
|
||||||
ck_assert(!matched);
|
ck_assert(!matched);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue