1
0
forked from 0ad/0ad

fix bug related to FileId use; now safer due to separate node_from_id function

This was SVN commit r3605.
This commit is contained in:
janwas 2006-03-05 07:35:42 +00:00
parent 4b3997f1f6
commit 6e15ed1e82

View File

@ -233,16 +233,16 @@ struct FileNode
{
const char* atom_fn;
FileId prev : 15;
FileId prev_id;
FileId next_id;
u32 visited : 1;
FileId next : 15;
u32 output : 1;
FileNode(const char* atom_fn_)
{
atom_fn = atom_fn_;
prev = next = NULL_ID;
prev_id = next_id = NULL_ID;
visited = output = 0;
}
};
@ -276,6 +276,12 @@ public:
return id;
}
FileNode* node_from_id(FileId id) const
{
debug_assert(id != NULL_ID);
return &(*nodes)[id-1];
}
FileId id_from_fn(const char* atom_fn) const
{
Map::const_iterator cit = map.find(atom_fn);
@ -567,25 +573,22 @@ class TourBuilder
}
};
// not const because we change the graph-related members
FileNodes& file_nodes;
bool has_cycle;
void detect_cycleR(FileId node)
void detect_cycleR(FileId id)
{
FileNode* pnode = &file_nodes[node];
FileNode* pnode = id_mgr.node_from_id(id);
pnode->visited = 1;
FileId next = pnode->next;
if(next != NULL_ID)
FileId next_id = pnode->next_id;
if(next_id != NULL_ID)
{
FileNode* pnext = &file_nodes[next];
FileNode* pnext = id_mgr.node_from_id(next_id);
if(pnext->visited)
has_cycle = true;
else
detect_cycleR(next);
detect_cycleR(next_id);
}
}
bool is_cycle_at(FileId node)
bool is_cycle_at(FileNodes& file_nodes, FileId node)
{
has_cycle = false;
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
@ -594,36 +597,34 @@ class TourBuilder
return has_cycle;
}
void try_add_edge(const Connection& c)
void try_add_edge(FileNodes& file_nodes, const Connection& c)
{
FileId first_id = cid_first(c.id);
FileId second_id = cid_second(c.id);
FileNode& first = file_nodes[first_id];
FileNode& second = file_nodes[second_id];
FileNode* first = id_mgr.node_from_id(first_id);
FileNode* second = id_mgr.node_from_id(second_id);
// one of them has already been hooked up - bail
if(first.next != NULL_ID || second.prev != NULL_ID)
if(first->next_id != NULL_ID || second->prev_id != NULL_ID)
return;
first.next = second_id;
second.prev = first_id;
first->next_id = second_id;
second->prev_id = first_id;
const bool introduced_cycle = is_cycle_at(second_id);
debug_assert(introduced_cycle == is_cycle_at(first_id));
const bool introduced_cycle = is_cycle_at(file_nodes, second_id);
debug_assert(introduced_cycle == is_cycle_at(file_nodes, first_id));
if(introduced_cycle)
{
// undo
first.next = second.prev = NULL_ID;
first->next_id = second->prev_id = NULL_ID;
return;
}
}
// pointer to this is returned by TourBuilder()!
std::vector<const char*>& fn_vector;
void output_chain(FileNode& node)
void output_chain(FileNode& node, std::vector<const char*>& fn_vector)
{
// early out: if this access was already visited, so must the entire
// early out: if this access was already visited, so must the entire
// chain of which it is a part. bail to save lots of time.
if(node.output)
return;
@ -631,34 +632,34 @@ class TourBuilder
// follow prev links starting with c until no more are left;
// start ends up the beginning of the chain including <c>.
FileNode* start = &node;
while(start->prev != NULL_ID)
start = &file_nodes[start->prev];
while(start->prev_id != NULL_ID)
start = id_mgr.node_from_id(start->prev_id);
// iterate over the chain - add to Filenames list and mark as visited
FileNode* cur = start;
do
for(;;)
{
if(!cur->output)
{
fn_vector.push_back(cur->atom_fn);
cur->output = 1;
}
cur = &file_nodes[cur->next];
if(cur->next_id == NULL_ID)
break;
cur = id_mgr.node_from_id(cur->next_id);
}
while(cur->next != NULL_ID);
}
public:
TourBuilder(FileNodes& file_nodes_, Connections& connections, std::vector<const char*>& fns_)
: file_nodes(file_nodes_), fn_vector(fns_)
TourBuilder(FileNodes& file_nodes, Connections& connections, std::vector<const char*>& fn_vector)
{
std::sort(connections.begin(), connections.end(), Occurrence_greater());
std::stable_sort(connections.begin(), connections.end(), Occurrence_greater());
for(Connections::iterator it = connections.begin(); it != connections.end(); ++it)
try_add_edge(*it);
try_add_edge(file_nodes, *it);
for(FileNodes::iterator it = file_nodes.begin(); it != file_nodes.end(); ++it)
output_chain(*it);
output_chain(*it, fn_vector);
}
// should never be copied; this also squelches warning
@ -705,12 +706,6 @@ archive.insert(atom_fn);
static bool should_rebuild_main_archive(const char* P_archive_path,
const char* trace_filename)
{
std::vector<const char*> diff;
set_difference(loose.begin(), loose.end(), archive.begin(), archive.end(), back_inserter(diff));
debug_printf("loose only:\n");
for(std::vector<const char*>::iterator it = diff.begin(); it != diff.end(); ++it)
debug_printf("%s\n", *it);
// if there's no trace file, no point in building a main archive.
struct stat s;
if(file_stat(trace_filename, &s) != ERR_OK)
@ -720,7 +715,6 @@ static bool should_rebuild_main_archive(const char* P_archive_path,
if(s.st_mtime >= vfs_mtime)
trace_enable(false);
const ssize_t loose_files_only = loose_file_total - non_loose_file_total;
if(loose_files_only >= REBUILD_MAIN_ARCHIVE_THRESHOLD)
return true;
@ -761,6 +755,7 @@ static void vfs_opt_init(const char* P_archive_fn_fmt, const char* trace_filenam
fn_vector.push_back(0);
Filenames V_fns = &fn_vector[0];
char archive_fn[PATH_MAX];
static NextNumberedFilenameInfo archive_nfi;
next_numbered_filename(P_archive_fn_fmt, &archive_nfi, archive_fn, false);