diff --git a/src/build/generators.jam b/src/build/generators.jam index de97b825b..ec7183a32 100644 --- a/src/build/generators.jam +++ b/src/build/generators.jam @@ -220,6 +220,18 @@ class generator self.name-prefix += $(m[3]:E="") ; self.name-postfix += $(m[4]:E="") ; } + + for local r in [ requirements ] + { + if $(r:G=) + { + self.property-requirements += $(r) ; + } + else + { + self.feature-requirements += $(r) ; + } + } # Note that 'transform' here, is the same as 'for_each'. sequence.transform type.validate : $(self.source-types) ; @@ -279,24 +291,9 @@ class generator # See if generator requirements are satisfied by 'properties'. Treat a # feature name in requirements (i.e. grist-only element), as matching # any value of the feature. - local all-requirements = [ requirements ] ; - local property-requirements feature-requirements ; - for local r in $(all-requirements) - { - if $(r:G=) - { - property-requirements += $(r) ; - } - else - { - feature-requirements += $(r) ; - } - } - - local properties-to-match = [ $(property-set-to-match).raw ] ; - if $(property-requirements) in $(properties-to-match) && - $(feature-requirements) in $(properties-to-match:G) + if [ $(property-set-to-match).contains-raw $(self.property-requirements) ] && + [ $(property-set-to-match).contains-features $(self.feature-requirements) ] { return true ; } diff --git a/src/build/property-set.jam b/src/build/property-set.jam index cfcabe01c..55cb55645 100644 --- a/src/build/property-set.jam +++ b/src/build/property-set.jam @@ -309,6 +309,17 @@ class property-set } } + # Returns true if the property-set has values for + # all the specified features + # + rule contains-features ( features * ) + { + if $(features) in $(self.raw:G) + { + return true ; + } + } + # private rule init-base ( ) @@ -395,6 +406,11 @@ if [ HAS_NATIVE_RULE class@property-set : get : 1 ] NATIVE_RULE class@property-set : get ; } +if [ HAS_NATIVE_RULE class@property-set : contains-features : 1 ] +{ + NATIVE_RULE class@property-set : contains-features ; +} + # Creates a new 'property-set' instance after checking that all properties are # valid and converting implicit properties into gristed form. # diff --git a/src/engine/modules/property-set.c b/src/engine/modules/property-set.c index 447aed079..21e35d5ab 100644 --- a/src/engine/modules/property-set.c +++ b/src/engine/modules/property-set.c @@ -13,6 +13,7 @@ #include "../native.h" #include "../compile.h" #include "../mem.h" +#include "../constants.h" #include "string.h" struct ps_map_entry @@ -259,6 +260,53 @@ LIST * property_set_get( FRAME * frame, int flags ) return result; } +/* binary search for the property value */ +LIST * property_set_contains_features( FRAME * frame, int flags ) +{ + OBJECT * varname = object_new( "self.raw" ); + LIST * props = var_get( frame->module, varname ); + LIST * features = lol_get( frame->args, 0 ); + LIST * result = L0; + LISTITER features_iter = list_begin( features ); + LISTITER features_end = list_end( features ) ; + object_free( varname ); + + for ( ; features_iter != features_end; ++features_iter ) + { + const char * name = object_str( list_item( features_iter ) ); + size_t name_len = strlen( name ); + LISTITER begin, end; + /* Assumes random access */ + begin = list_begin( props ), end = list_end( props ); + + while ( 1 ) + { + ptrdiff_t diff = (end - begin); + LISTITER mid = begin + diff / 2; + int res; + if ( diff == 0 ) + { + /* The feature is missing */ + return L0; + } + res = strncmp( object_str( list_item( mid ) ), name, name_len ); + if ( res < 0 ) + { + begin = mid + 1; + } + else if ( res > 0 ) + { + end = mid; + } + else /* We've found the property */ + { + break; + } + } + } + return list_new( object_copy( constant_true ) ); +} + void init_property_set() { { @@ -269,6 +317,10 @@ void init_property_set() char const * args[] = { "feature", 0 }; declare_native_rule( "class@property-set", "get", args, property_set_get, 1 ); } + { + char const * args[] = { "features", "*", 0 }; + declare_native_rule( "class@property-set", "contains-features", args, property_set_contains_features, 1 ); + } ps_map_init( &all_property_sets ); }