attr: remove maybe-real, maybe-macro from git_attr
Whether or not a git attribute is real or a macro isn't a property of the attribute but rather it depends on the attribute stack (which .gitattribute files were read). This patch removes the 'maybe_real' and 'maybe_macro' fields in a git_attr and instead adds the 'macro' field to a attr_check_item. The 'macro' indicates (if non-NULL) that a particular attribute is a macro for the given attribute stack. It's populated, through a quick scan of the attribute stack, with the match_attr that corresponds to the macro's definition. This way the attribute stack only needs to be scanned a single time prior to attribute collection instead of each time a macro needs to be expanded. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									685b292575
								
							
						
					
					
						commit
						60a12722ac
					
				
							
								
								
									
										75
									
								
								attr.c
								
								
								
								
							
							
						
						
									
										75
									
								
								attr.c
								
								
								
								
							|  | @ -30,20 +30,9 @@ static const char git_attr__unknown[] = "(builtin)unknown"; | ||||||
|  |  | ||||||
| struct git_attr { | struct git_attr { | ||||||
| 	int attr_nr; /* unique attribute number */ | 	int attr_nr; /* unique attribute number */ | ||||||
| 	int maybe_macro; |  | ||||||
| 	int maybe_real; |  | ||||||
| 	char name[FLEX_ARRAY]; /* attribute name */ | 	char name[FLEX_ARRAY]; /* attribute name */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * NEEDSWORK: maybe-real, maybe-macro are not property of |  | ||||||
|  * an attribute, as it depends on what .gitattributes are |  | ||||||
|  * read.  Once we introduce per git_attr_check attr_stack |  | ||||||
|  * and check_all_attr, the optimization based on them will |  | ||||||
|  * become unnecessary and can go away.  So is this variable. |  | ||||||
|  */ |  | ||||||
| static int cannot_trust_maybe_real; |  | ||||||
|  |  | ||||||
| const char *git_attr_name(const struct git_attr *attr) | const char *git_attr_name(const struct git_attr *attr) | ||||||
| { | { | ||||||
| 	return attr->name; | 	return attr->name; | ||||||
|  | @ -142,6 +131,12 @@ static void attr_hashmap_add(struct attr_hashmap *map, | ||||||
| struct all_attrs_item { | struct all_attrs_item { | ||||||
| 	const struct git_attr *attr; | 	const struct git_attr *attr; | ||||||
| 	const char *value; | 	const char *value; | ||||||
|  | 	/* | ||||||
|  | 	 * If 'macro' is non-NULL, indicates that 'attr' is a macro based on | ||||||
|  | 	 * the current attribute stack and contains a pointer to the match_attr | ||||||
|  | 	 * definition of the macro | ||||||
|  | 	 */ | ||||||
|  | 	const struct match_attr *macro; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  | @ -187,6 +182,7 @@ static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check) | ||||||
| 	 */ | 	 */ | ||||||
| 	for (i = 0; i < check->all_attrs_nr; i++) { | 	for (i = 0; i < check->all_attrs_nr; i++) { | ||||||
| 		check->all_attrs[i].value = ATTR__UNKNOWN; | 		check->all_attrs[i].value = ATTR__UNKNOWN; | ||||||
|  | 		check->all_attrs[i].macro = NULL; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -238,8 +234,6 @@ static struct git_attr *git_attr_internal(const char *name, int namelen) | ||||||
| 	if (!a) { | 	if (!a) { | ||||||
| 		FLEX_ALLOC_MEM(a, name, name, namelen); | 		FLEX_ALLOC_MEM(a, name, name, namelen); | ||||||
| 		a->attr_nr = g_attr_hashmap.map.size; | 		a->attr_nr = g_attr_hashmap.map.size; | ||||||
| 		a->maybe_real = 0; |  | ||||||
| 		a->maybe_macro = 0; |  | ||||||
|  |  | ||||||
| 		attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a); | 		attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a); | ||||||
| 		assert(a->attr_nr == (g_attr_hashmap.map.size - 1)); | 		assert(a->attr_nr == (g_attr_hashmap.map.size - 1)); | ||||||
|  | @ -402,7 +396,6 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, | ||||||
| 		      (is_macro ? 0 : namelen + 1)); | 		      (is_macro ? 0 : namelen + 1)); | ||||||
| 	if (is_macro) { | 	if (is_macro) { | ||||||
| 		res->u.attr = git_attr_internal(name, namelen); | 		res->u.attr = git_attr_internal(name, namelen); | ||||||
| 		res->u.attr->maybe_macro = 1; |  | ||||||
| 	} else { | 	} else { | ||||||
| 		char *p = (char *)&(res->state[num_attr]); | 		char *p = (char *)&(res->state[num_attr]); | ||||||
| 		memcpy(p, name, namelen); | 		memcpy(p, name, namelen); | ||||||
|  | @ -423,10 +416,6 @@ static struct match_attr *parse_attr_line(const char *line, const char *src, | ||||||
| 	/* Second pass to fill the attr_states */ | 	/* Second pass to fill the attr_states */ | ||||||
| 	for (cp = states, i = 0; *cp; i++) { | 	for (cp = states, i = 0; *cp; i++) { | ||||||
| 		cp = parse_attr(src, lineno, cp, &(res->state[i])); | 		cp = parse_attr(src, lineno, cp, &(res->state[i])); | ||||||
| 		if (!is_macro) |  | ||||||
| 			res->state[i].attr->maybe_real = 1; |  | ||||||
| 		if (res->state[i].attr->maybe_macro) |  | ||||||
| 			cannot_trust_maybe_real = 1; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	strbuf_release(&pattern); | 	strbuf_release(&pattern); | ||||||
|  | @ -904,7 +893,7 @@ static int path_matches(const char *pathname, int pathlen, | ||||||
| static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem); | static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem); | ||||||
|  |  | ||||||
| static int fill_one(const char *what, struct all_attrs_item *all_attrs, | static int fill_one(const char *what, struct all_attrs_item *all_attrs, | ||||||
| 		    struct match_attr *a, int rem) | 		    const struct match_attr *a, int rem) | ||||||
| { | { | ||||||
| 	int i; | 	int i; | ||||||
|  |  | ||||||
|  | @ -945,24 +934,34 @@ static int fill(const char *path, int pathlen, int basename_offset, | ||||||
|  |  | ||||||
| static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem) | static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem) | ||||||
| { | { | ||||||
| 	struct attr_stack *stk; | 	const struct all_attrs_item *item = &all_attrs[nr]; | ||||||
| 	int i; |  | ||||||
|  |  | ||||||
| 	if (all_attrs[nr].value != ATTR__TRUE || | 	if (item->macro && item->value == ATTR__TRUE) | ||||||
| 	    !all_attrs[nr].attr->maybe_macro) | 		return fill_one("expand", all_attrs, item->macro, rem); | ||||||
|  | 	else | ||||||
| 		return rem; | 		return rem; | ||||||
|  | } | ||||||
|  |  | ||||||
| 	for (stk = attr_stack; stk; stk = stk->prev) { | /* | ||||||
| 		for (i = stk->num_matches - 1; 0 <= i; i--) { |  * Marks the attributes which are macros based on the attribute stack. | ||||||
| 			struct match_attr *ma = stk->attrs[i]; |  * This prevents having to search through the attribute stack each time | ||||||
| 			if (!ma->is_macro) |  * a macro needs to be expanded during the fill stage. | ||||||
| 				continue; |  */ | ||||||
| 			if (ma->u.attr->attr_nr == nr) | static void determine_macros(struct all_attrs_item *all_attrs, | ||||||
| 				return fill_one("expand", all_attrs, ma, rem); | 			     const struct attr_stack *stack) | ||||||
|  | { | ||||||
|  | 	for (; stack; stack = stack->prev) { | ||||||
|  | 		int i; | ||||||
|  | 		for (i = stack->num_matches - 1; i >= 0; i--) { | ||||||
|  | 			const struct match_attr *ma = stack->attrs[i]; | ||||||
|  | 			if (ma->is_macro) { | ||||||
|  | 				int n = ma->u.attr->attr_nr; | ||||||
|  | 				if (!all_attrs[n].macro) { | ||||||
|  | 					all_attrs[n].macro = ma; | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return rem; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  | @ -992,15 +991,15 @@ static void collect_some_attrs(const char *path, struct attr_check *check) | ||||||
|  |  | ||||||
| 	prepare_attr_stack(path, dirlen); | 	prepare_attr_stack(path, dirlen); | ||||||
| 	all_attrs_init(&g_attr_hashmap, check); | 	all_attrs_init(&g_attr_hashmap, check); | ||||||
|  | 	determine_macros(check->all_attrs, attr_stack); | ||||||
|  |  | ||||||
| 	if (check->nr && !cannot_trust_maybe_real) { | 	if (check->nr) { | ||||||
| 		rem = 0; | 		rem = 0; | ||||||
| 		for (i = 0; i < check->nr; i++) { | 		for (i = 0; i < check->nr; i++) { | ||||||
| 			const struct git_attr *a = check->items[i].attr; | 			int n = check->items[i].attr->attr_nr; | ||||||
| 			if (!a->maybe_real) { | 			struct all_attrs_item *item = &check->all_attrs[n]; | ||||||
| 				struct all_attrs_item *c; | 			if (item->macro) { | ||||||
| 				c = check->all_attrs + a->attr_nr; | 				item->value = ATTR__UNSET; | ||||||
| 				c->value = ATTR__UNSET; |  | ||||||
| 				rem++; | 				rem++; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Brandon Williams
						Brandon Williams