2 * Copyright 2013 Steven Watanabe
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
10 #include "../modules.h"
12 #include "../variable.h"
13 #include "../native.h"
14 #include "../compile.h"
16 #include "../constants.h"
21 struct ps_map_entry
* next
;
28 struct ps_map_entry
* * table
;
33 static unsigned list_hash(LIST
* key
)
35 unsigned int hash
= 0;
36 LISTITER iter
= list_begin( key
), end
= list_end( key
);
37 for ( ; iter
!= end
; ++iter
)
39 hash
= hash
* 2147059363 + object_hash( list_item( iter
) );
44 static int list_equal( LIST
* lhs
, LIST
* rhs
)
46 LISTITER lhs_iter
, lhs_end
, rhs_iter
;
47 if ( list_length( lhs
) != list_length( rhs
) )
51 lhs_iter
= list_begin( lhs
);
52 lhs_end
= list_end( lhs
);
53 rhs_iter
= list_begin( rhs
);
54 for ( ; lhs_iter
!= lhs_end
; ++lhs_iter
, ++rhs_iter
)
56 if ( ! object_equal( list_item( lhs_iter
), list_item( rhs_iter
) ) )
64 static void ps_map_init( struct ps_map
* map
)
69 map
->table
= BJAM_MALLOC( map
->table_size
* sizeof( struct ps_map_entry
* ) );
70 for ( i
= 0; i
< map
->table_size
; ++i
)
72 map
->table
[ i
] = NULL
;
76 static void ps_map_destroy( struct ps_map
* map
)
79 for ( i
= 0; i
< map
->table_size
; ++i
)
81 struct ps_map_entry
* pos
;
82 for ( pos
= map
->table
[ i
]; pos
; )
84 struct ps_map_entry
* tmp
= pos
->next
;
85 object_free( pos
->value
);
90 BJAM_FREE( map
->table
);
93 static void ps_map_rehash( struct ps_map
* map
)
95 struct ps_map old
= *map
;
97 map
->table
= BJAM_MALLOC( map
->table_size
* 2 * sizeof( struct ps_map_entry
* ) );
99 for ( i
= 0; i
< map
->table_size
; ++i
)
101 map
->table
[ i
] = NULL
;
103 for ( i
= 0; i
< old
.table_size
; ++i
)
105 struct ps_map_entry
* pos
;
106 for ( pos
= old
.table
[ i
]; pos
; )
108 struct ps_map_entry
* tmp
= pos
->next
;
110 unsigned hash_val
= list_hash( pos
->key
);
111 unsigned bucket
= hash_val
% map
->table_size
;
112 pos
->next
= map
->table
[ bucket
];
113 map
->table
[ bucket
] = pos
;
118 BJAM_FREE( old
.table
);
121 static struct ps_map_entry
* ps_map_insert(struct ps_map
* map
, LIST
* key
)
123 unsigned hash_val
= list_hash( key
);
124 unsigned bucket
= hash_val
% map
->table_size
;
125 struct ps_map_entry
* pos
;
126 for ( pos
= map
->table
[bucket
]; pos
; pos
= pos
->next
)
128 if ( list_equal( pos
->key
, key
) )
132 if ( map
->num_elems
>= map
->table_size
)
134 ps_map_rehash( map
);
135 bucket
= hash_val
% map
->table_size
;
137 pos
= BJAM_MALLOC( sizeof( struct ps_map_entry
) );
138 pos
->next
= map
->table
[bucket
];
141 map
->table
[bucket
] = pos
;
146 static struct ps_map all_property_sets
;
148 LIST
* property_set_create( FRAME
* frame
, int flags
)
150 LIST
* properties
= lol_get( frame
->args
, 0 );
151 LIST
* sorted
= list_sort( properties
);
152 LIST
* unique
= list_unique( sorted
);
153 struct ps_map_entry
* pos
= ps_map_insert( &all_property_sets
, unique
);
158 return list_new( object_copy( pos
->value
) );
162 OBJECT
* rulename
= object_new( "new" );
163 OBJECT
* varname
= object_new( "self.raw" );
164 LIST
* val
= call_rule( rulename
, frame
,
165 list_new( object_new( "property-set" ) ), 0 );
167 object_free( rulename
);
168 pos
->value
= object_copy( list_front( val
) );
169 var_set( bindmodule( pos
->value
), varname
, unique
, VAR_SET
);
170 object_free( varname
);
172 for ( iter
= list_begin( unique
), end
= list_end( unique
); iter
!= end
; ++iter
)
174 const char * str
= object_str( list_item( iter
) );
175 if ( str
[ 0 ] != '<' || ! strchr( str
, '>' ) )
178 string_new( message
);
179 string_append( message
, "Invalid property: '" );
180 string_append( message
, str
);
181 string_append( message
, "'" );
182 rulename
= object_new( "errors.error" );
183 call_rule( rulename
, frame
,
184 list_new( object_new( message
->value
) ), 0 );
186 string_free( message
);
187 object_free( rulename
);
195 /* binary search for the property value */
196 LIST
* property_set_get( FRAME
* frame
, int flags
)
198 OBJECT
* varname
= object_new( "self.raw" );
199 LIST
* props
= var_get( frame
->module
, varname
);
200 const char * name
= object_str( list_front( lol_get( frame
->args
, 0 ) ) );
201 size_t name_len
= strlen( name
);
204 object_free( varname
);
206 /* Assumes random access */
207 begin
= list_begin( props
), end
= list_end( props
);
211 ptrdiff_t diff
= (end
- begin
);
212 LISTITER mid
= begin
+ diff
/ 2;
218 res
= strncmp( object_str( list_item( mid
) ), name
, name_len
);
227 else /* We've found the property */
229 /* Find the beginning of the group */
231 while ( tmp
> begin
)
234 res
= strncmp( object_str( list_item( tmp
) ), name
, name_len
);
242 /* Find the end of the group */
246 res
= strncmp( object_str( list_item( tmp
) ), name
, name_len
);
247 if ( res
!= 0 ) break;
255 for ( ; begin
!= end
; ++begin
)
257 result
= list_push_back( result
,
258 object_new( object_str( list_item( begin
) ) + name_len
) );
264 /* binary search for the property value */
265 LIST
* property_set_contains_features( FRAME
* frame
, int flags
)
267 OBJECT
* varname
= object_new( "self.raw" );
268 LIST
* props
= var_get( frame
->module
, varname
);
269 LIST
* features
= lol_get( frame
->args
, 0 );
271 LISTITER features_iter
= list_begin( features
);
272 LISTITER features_end
= list_end( features
) ;
273 object_free( varname
);
275 for ( ; features_iter
!= features_end
; ++features_iter
)
277 const char * name
= object_str( list_item( features_iter
) );
278 size_t name_len
= strlen( name
);
280 /* Assumes random access */
281 begin
= list_begin( props
), end
= list_end( props
);
285 ptrdiff_t diff
= (end
- begin
);
286 LISTITER mid
= begin
+ diff
/ 2;
290 /* The feature is missing */
293 res
= strncmp( object_str( list_item( mid
) ), name
, name_len
);
302 else /* We've found the property */
308 return list_new( object_copy( constant_true
) );
311 void init_property_set()
314 char const * args
[] = { "raw-properties", "*", 0 };
315 declare_native_rule( "property-set", "create", args
, property_set_create
, 1 );
318 char const * args
[] = { "feature", 0 };
319 declare_native_rule( "class@property-set", "get", args
, property_set_get
, 1 );
322 char const * args
[] = { "features", "*", 0 };
323 declare_native_rule( "class@property-set", "contains-features", args
, property_set_contains_features
, 1 );
325 ps_map_init( &all_property_sets
);
328 void property_set_done()
330 ps_map_destroy( &all_property_sets
);