Move criteria.matches() to C to gain back some performance lost to filter prefixes
This commit is contained in:
parent
28cfa55886
commit
0f713d5c39
@ -8,7 +8,7 @@
|
|||||||
-- Copyright (c) 2012-2014 Jason Perkins and the Premake project
|
-- Copyright (c) 2012-2014 Jason Perkins and the Premake project
|
||||||
--
|
--
|
||||||
|
|
||||||
premake.criteria = {}
|
premake.criteria = criteria
|
||||||
local criteria = premake.criteria
|
local criteria = premake.criteria
|
||||||
|
|
||||||
|
|
||||||
@ -43,15 +43,18 @@
|
|||||||
end
|
end
|
||||||
|
|
||||||
local parts = path.wildcards(term)
|
local parts = path.wildcards(term)
|
||||||
|
local isWildcard = (parts ~= term)
|
||||||
parts = parts:explode(" or ")
|
parts = parts:explode(" or ")
|
||||||
|
|
||||||
for i, part in ipairs(parts) do
|
for i, part in ipairs(parts) do
|
||||||
if part:startswith("not ") then
|
if part:startswith("not ") then
|
||||||
table.insert(pattern, "not")
|
table.insert(pattern, "not")
|
||||||
table.insert(pattern, part:sub(5))
|
part = part:sub(5)
|
||||||
else
|
|
||||||
table.insert(pattern, part)
|
|
||||||
end
|
end
|
||||||
|
if isWildcard then
|
||||||
|
table.insert(pattern, "%%")
|
||||||
|
end
|
||||||
|
table.insert(pattern, part)
|
||||||
end
|
end
|
||||||
|
|
||||||
table.insert(patterns, pattern)
|
table.insert(patterns, pattern)
|
||||||
@ -62,101 +65,3 @@
|
|||||||
crit.patterns = patterns
|
crit.patterns = patterns
|
||||||
return crit
|
return crit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
---
|
|
||||||
-- Determine if this criteria is met by the provided list of context terms.
|
|
||||||
--
|
|
||||||
-- @param crit
|
|
||||||
-- The criteria to be tested.
|
|
||||||
-- @param context
|
|
||||||
-- The list of context terms to test against, provided as a list of
|
|
||||||
-- lowercase strings.
|
|
||||||
-- @return
|
|
||||||
-- True if all criteria are satisfied by the context.
|
|
||||||
---
|
|
||||||
|
|
||||||
function criteria.matches(crit, context)
|
|
||||||
-- If the context specifies a filename, I should only match against
|
|
||||||
-- blocks targeted at that file specifically. This way, files only
|
|
||||||
-- pick up the settings that a different from the main project.
|
|
||||||
local filename = context.files
|
|
||||||
local filematched = false
|
|
||||||
|
|
||||||
-- Test one value from the context against a part of a pattern
|
|
||||||
function testValue(value, part)
|
|
||||||
if type(value) == "table" then
|
|
||||||
for i = 1, #value do
|
|
||||||
if testValue(value[i], part) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if value and value:match(part) == value then
|
|
||||||
return true;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Test one part of one pattern against the provided context
|
|
||||||
function testContext(prefix, part, assertion)
|
|
||||||
if prefix then
|
|
||||||
local result = testValue(context[prefix], part)
|
|
||||||
if prefix == "files" and result == assertion then
|
|
||||||
filematched = true
|
|
||||||
end
|
|
||||||
if result then
|
|
||||||
return assertion
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if filename and assertion and filename:match(part) == filename then
|
|
||||||
filematched = true
|
|
||||||
return assertion
|
|
||||||
end
|
|
||||||
|
|
||||||
for prefix, value in pairs(context) do
|
|
||||||
if testValue(value, part) then
|
|
||||||
return assertion
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return not assertion
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Test an individual pattern in this criteria's list of patterns
|
|
||||||
function testPattern(pattern)
|
|
||||||
local n = #pattern
|
|
||||||
local assertion = true
|
|
||||||
|
|
||||||
for i = 1, n do
|
|
||||||
local part = pattern[i]
|
|
||||||
if part == "not" then
|
|
||||||
assertion = false
|
|
||||||
else
|
|
||||||
if testContext(pattern.prefix, part, assertion) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
assertion = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Iterate the list of patterns and test each in turn
|
|
||||||
local n = #crit.patterns
|
|
||||||
for i = 1, n do
|
|
||||||
local pattern = crit.patterns[i]
|
|
||||||
if not testPattern(pattern) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if filename and not filematched then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
283
src/host/criteria_matches.c
Normal file
283
src/host/criteria_matches.c
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
/**
|
||||||
|
* \file criteria_matches.c
|
||||||
|
* \brief Determine if this criteria is met by the provided filter terms.
|
||||||
|
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "premake.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return value:match(pattern) == value
|
||||||
|
*/
|
||||||
|
static int match(lua_State* L, const char* value, const char* pattern, int wildcard)
|
||||||
|
{
|
||||||
|
if (wildcard) {
|
||||||
|
const char* result;
|
||||||
|
int matched = 0;
|
||||||
|
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
|
lua_pushvalue(L, 4);
|
||||||
|
lua_pushstring(L, value);
|
||||||
|
lua_pushstring(L, pattern);
|
||||||
|
lua_call(L, 2, 1);
|
||||||
|
|
||||||
|
if (lua_isstring(L, -1)) {
|
||||||
|
result = lua_tostring(L, -1);
|
||||||
|
matched = (strcmp(value, result) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_settop(L, top);
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (strcmp(value, pattern) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compares the value on the top of the stack to the provided
|
||||||
|
* part, which is a Lua pattern string.
|
||||||
|
*/
|
||||||
|
static int testValue(lua_State* L, const char* part, const int wildcard)
|
||||||
|
{
|
||||||
|
const char* value;
|
||||||
|
size_t i, n;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
if type(value) == "table" then
|
||||||
|
for i = 1, #value do
|
||||||
|
if testValue(value[i], part) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if value and value:match(part) == value then
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (lua_istable(L, -1)) {
|
||||||
|
n = lua_objlen(L, -1);
|
||||||
|
for (i = 1; i <= n; ++i) {
|
||||||
|
lua_rawgeti(L, -1, i);
|
||||||
|
result = testValue(L, part, wildcard);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
if (result) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = lua_tostring(L, -1);
|
||||||
|
if (value && match(L, value, part, wildcard)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The context is a set of key-value pairs, something like:
|
||||||
|
* {
|
||||||
|
* action = "vs2010",
|
||||||
|
* configurations = "Debug",
|
||||||
|
* system = "windows",
|
||||||
|
* files = "/absolute/path/to/hello.cpp",
|
||||||
|
* -- and so on...
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
static int testContext(lua_State* L, const char* prefix, const char* part,
|
||||||
|
const int assertion, const int wildcard,
|
||||||
|
const char* filename, int* fileMatched)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if prefix then
|
||||||
|
local result = testValue(context[prefix], part, wildcard)
|
||||||
|
if result == assertion and prefix == "files" then
|
||||||
|
filematched = true
|
||||||
|
end
|
||||||
|
if result then
|
||||||
|
return assertion
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if filename and assertion and filename:match(part) == filename then
|
||||||
|
filematched = true
|
||||||
|
return assertion
|
||||||
|
end
|
||||||
|
|
||||||
|
for prefix, value in pairs(context) do
|
||||||
|
if testValue(value, part, wildcard) then
|
||||||
|
return assertion
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
|
||||||
|
int result;
|
||||||
|
if (prefix) {
|
||||||
|
lua_getfield(L, 2, prefix);
|
||||||
|
result = testValue(L, part, wildcard);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
if (result == assertion && strcmp(prefix, "files") == 0) {
|
||||||
|
(*fileMatched) = 1;
|
||||||
|
}
|
||||||
|
if (result) {
|
||||||
|
return assertion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (filename && assertion && match(L, filename, part, wildcard)) {
|
||||||
|
(*fileMatched) = 1;
|
||||||
|
return assertion;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, 2)) {
|
||||||
|
if (testValue(L, part, wildcard)) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
return assertion;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!assertion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Patterns are represented as an array of string values.
|
||||||
|
* "windows" = { "windows" }
|
||||||
|
* "not windows" = { "not", "windows" }
|
||||||
|
* "windows or linux" = { "windows", "linux" }
|
||||||
|
*
|
||||||
|
* If the patterns is targeted at a specific prefix, that is stored
|
||||||
|
* as a keyed value.
|
||||||
|
*
|
||||||
|
* "files:**.c" = { prefix="files", "**.c" }
|
||||||
|
*/
|
||||||
|
static int testPattern(lua_State* L, const char* filename, int* fileMatched)
|
||||||
|
{
|
||||||
|
const char* prefix;
|
||||||
|
const char* part;
|
||||||
|
size_t i, n;
|
||||||
|
int assertion = 1;
|
||||||
|
int wildcard = 0;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
/* prefix = pattern.prefix */
|
||||||
|
lua_getfield(L, -1, "prefix");
|
||||||
|
prefix = lua_tostring(L, -1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
for i = 1, #pattern do
|
||||||
|
part = pattern[i]
|
||||||
|
if part == "not" then
|
||||||
|
assertion = false
|
||||||
|
else
|
||||||
|
if testContext(pattern.prefix, part, assertion) then
|
||||||
|
result = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
assertion = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
|
||||||
|
n = lua_objlen(L, -2);
|
||||||
|
for (i = 1; i <= n; ++i) {
|
||||||
|
lua_rawgeti(L, -2, i);
|
||||||
|
part = lua_tostring(L, -1);
|
||||||
|
|
||||||
|
if (strcmp(part, "not") == 0) {
|
||||||
|
assertion = 0;
|
||||||
|
}
|
||||||
|
else if (part[0] == '%' && part[1] == '%') {
|
||||||
|
wildcard = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (testContext(L, prefix, part, assertion, wildcard, filename, fileMatched)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
assertion = 1;
|
||||||
|
wildcard = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int criteria_matches(lua_State* L)
|
||||||
|
{
|
||||||
|
/* stack [1] = criteria */
|
||||||
|
/* stack [2] = context */
|
||||||
|
|
||||||
|
const char* filename;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
int matched = 1;
|
||||||
|
int fileMatched = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Cache string.match for a quicker lookup in match() above
|
||||||
|
stack[3] = string
|
||||||
|
stack[4] = string.match
|
||||||
|
*/
|
||||||
|
|
||||||
|
lua_getglobal(L, "string");
|
||||||
|
lua_getfield(L, -1, "match");
|
||||||
|
|
||||||
|
/* filename = context.files */
|
||||||
|
|
||||||
|
lua_getfield(L, 2, "files");
|
||||||
|
filename = lua_tostring(L, -1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
for i, pattern in pairs(criteria.patterns) do
|
||||||
|
if not testPattern(pattern) then
|
||||||
|
matched = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
*/
|
||||||
|
|
||||||
|
lua_getfield(L, 1, "patterns");
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2)) {
|
||||||
|
if (!testPattern(L, filename, &fileMatched)) {
|
||||||
|
matched = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
if matched and filename and not filematched then
|
||||||
|
matched = false
|
||||||
|
end
|
||||||
|
return matched
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (matched && filename && !fileMatched) {
|
||||||
|
matched = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_settop(L, top);
|
||||||
|
lua_pushboolean(L, matched);
|
||||||
|
return 1;
|
||||||
|
}
|
@ -35,6 +35,11 @@ extern const char* builtin_scripts[];
|
|||||||
|
|
||||||
|
|
||||||
/* Built-in functions */
|
/* Built-in functions */
|
||||||
|
static const luaL_Reg criteria_functions[] = {
|
||||||
|
{ "matches", criteria_matches },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static const luaL_Reg path_functions[] = {
|
static const luaL_Reg path_functions[] = {
|
||||||
{ "getabsolute", path_getabsolute },
|
{ "getabsolute", path_getabsolute },
|
||||||
{ "getrelative", path_getrelative },
|
{ "getrelative", path_getrelative },
|
||||||
@ -79,6 +84,7 @@ static const luaL_Reg string_functions[] = {
|
|||||||
*/
|
*/
|
||||||
int premake_init(lua_State* L)
|
int premake_init(lua_State* L)
|
||||||
{
|
{
|
||||||
|
luaL_register(L, "criteria", criteria_functions);
|
||||||
luaL_register(L, "path", path_functions);
|
luaL_register(L, "path", path_functions);
|
||||||
luaL_register(L, "os", os_functions);
|
luaL_register(L, "os", os_functions);
|
||||||
luaL_register(L, "string", string_functions);
|
luaL_register(L, "string", string_functions);
|
||||||
|
@ -62,6 +62,7 @@ void do_translate(char* value, const char sep);
|
|||||||
|
|
||||||
|
|
||||||
/* Built-in functions */
|
/* Built-in functions */
|
||||||
|
int criteria_matches(lua_State* L);
|
||||||
int path_getabsolute(lua_State* L);
|
int path_getabsolute(lua_State* L);
|
||||||
int path_getrelative(lua_State* L);
|
int path_getrelative(lua_State* L);
|
||||||
int path_isabsolute(lua_State* L);
|
int path_isabsolute(lua_State* L);
|
||||||
|
Loading…
Reference in New Issue
Block a user