-
Notifications
You must be signed in to change notification settings - Fork 2
/
edge_list.cc
139 lines (127 loc) · 4.16 KB
/
edge_list.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include "edge_list.h"
#include <cstring>
#include <getopt.h>
// Logging macro. Flush right away since Emu hardware usually doesn't
#define LOG(...) fprintf(stdout, __VA_ARGS__); fflush(stdout);
static const struct option header_options[] = {
{"num_vertices" , required_argument},
{"num_edges" , required_argument},
{"is_sorted" , no_argument},
{"is_deduped" , no_argument},
{"is_permuted" , no_argument},
{"is_directed" , no_argument},
{"is_undirected" , no_argument},
{"format" , required_argument},
{NULL}
};
void
parse_edge_list_file_header(FILE* fp, edge_list_file_header *header)
{
// Get the first line of text from the file
char line[256];
if (!fgets(line, 256, fp)) {
LOG("Failed to read edge list header\n");
exit(1);
}
size_t line_len = strlen(line);
header->header_length = line_len;
// Strip endline character
if (line[line_len-1] != '\n') {
LOG("Invalid edge list file header\n");
exit(1);
}
line[--line_len] = '\0';
// Split on spaces
// Assumption: never more than 32 arguments in header
const int max_argc = 32;
char * argv[max_argc];
// Leave empty slot for expected program name
argv[0] = strdup("edge list header");
int argc = 1;
char * token = strtok(line, " ");
while (token && argc < max_argc) {
argv[argc++] = token;
token = strtok(NULL, " ");
}
// Null terminator for argv
argv[argc] = NULL;
// Assume default values
header->num_vertices = -1;
header->num_edges = -1;
header->is_sorted = false;
header->is_deduped = false;
header->format = NULL;
// Reset getopt
optind = 1;
// Parse header like an option string
int option_index;
while (true)
{
int c = getopt_long(argc, argv, "", header_options, &option_index);
// Done parsing
if (c == -1) { break; }
// Invalid arg
if (c == '?') {
LOG( "Invalid field edge list header\n");
exit(1);
}
const char* option_name = header_options[option_index].name;
if (!strcmp(option_name, "num_vertices")) {
header->num_vertices = atol(optarg);
} else if (!strcmp(option_name, "num_edges")) {
header->num_edges = atol(optarg);
} else if (!strcmp(option_name, "is_sorted")) {
header->is_sorted = true;
} else if (!strcmp(option_name, "is_deduped")) {
header->is_deduped = true;
} else if (!strcmp(option_name, "format")) {
header->format = strdup(optarg);
}
}
// It's up to the caller to validate and interpret the arguments
}
void
load_edge_list_local(const char* path, edge_list * el)
{
LOG("Opening %s...\n", path);
FILE* fp = fopen(path, "rb");
if (fp == NULL) {
LOG("Unable to open %s\n", path);
exit(1);
}
edge_list_file_header header;
parse_edge_list_file_header(fp, &header);
if (header.num_vertices <= 0 || header.num_edges <= 0) {
LOG("Invalid graph size in header\n");
exit(1);
}
// TODO add support for other formats
if (!header.format || !!strcmp(header.format, "el64")) {
LOG("Unsuppported edge list format %s\n", header.format);
exit(1);
}
// Future implementations may be able to handle duplicates
if (!header.is_deduped) {
LOG("Edge list must be sorted and deduped.");
exit(1);
}
el->num_edges = header.num_edges;
el->num_vertices = header.num_vertices;
el->edges = (edge*)malloc(sizeof(edge) * header.num_edges);
if (el->edges == NULL) {
LOG("Failed to allocate memory for %ld edges\n", header.num_edges);
exit(1);
}
LOG("Loading %li edges from %s...\n", header.num_edges, path);
size_t rc = fread(&el->edges[0], sizeof(edge), header.num_edges, fp);
if (rc != (size_t)header.num_edges) {
LOG("Failed to load edge list from %s ", path);
if (feof(fp)) {
LOG("unexpected EOF\n");
} else if (ferror(fp)) {
perror("fread returned error\n");
}
exit(1);
}
fclose(fp);
}