Skip to content

Commit 0577159

Browse files
authored
Merge pull request #1757 from Smit-create/dict_c
C: Codegen dictionary for types with no hash
2 parents d731c7a + f403c41 commit 0577159

File tree

4 files changed

+172
-32
lines changed

4 files changed

+172
-32
lines changed

integration_tests/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,12 +383,12 @@ RUN(NAME test_dict_01 LABELS cpython llvm c)
383383
RUN(NAME test_dict_02 LABELS cpython llvm c)
384384
RUN(NAME test_dict_03 LABELS cpython llvm)
385385
RUN(NAME test_dict_04 LABELS cpython llvm)
386-
RUN(NAME test_dict_05 LABELS cpython llvm)
386+
RUN(NAME test_dict_05 LABELS cpython llvm c)
387387
RUN(NAME test_dict_06 LABELS cpython llvm c)
388-
RUN(NAME test_dict_07 LABELS cpython llvm)
388+
RUN(NAME test_dict_07 LABELS cpython llvm c)
389389
RUN(NAME test_dict_08 LABELS cpython llvm c)
390390
RUN(NAME test_dict_09 LABELS cpython llvm c)
391-
RUN(NAME test_dict_10 LABELS cpython llvm) # TODO: Add support of dict with string in C backend
391+
RUN(NAME test_dict_10 LABELS cpython llvm c)
392392
RUN(NAME test_dict_11 LABELS cpython llvm c)
393393
RUN(NAME test_dict_bool LABELS cpython llvm)
394394
RUN(NAME test_for_loop LABELS cpython llvm c)

integration_tests/test_dict_07.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
from lpython import i32
2+
3+
14
def fill_smalltocapital() -> dict[str, str]:
2-
return {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E',
3-
'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J',
4-
'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O',
5-
'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T',
6-
'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y',
5+
return {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E',
6+
'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J',
7+
'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O',
8+
'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T',
9+
'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y',
710
'z': 'Z'}
811

912
def test_dict():
10-
i : i32
13+
i: i32
1114
smalltocaps: dict[str, str]
1215
smalltocaps = fill_smalltocapital()
1316

integration_tests/test_dict_10.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1+
from lpython import i32
2+
13
# test case for passing dict with key-value as strings as argument to function
24

35
def test_assertion(smalltocaps: dict[str, str]):
4-
i : i32
6+
i: i32
57
assert len(smalltocaps) == 26
68
for i in range(97, 97 + 26):
79
assert smalltocaps[chr(i)] == chr(i - 32)
810

911
def test_dict():
1012
smalltocaps: dict[str, str]
11-
smalltocaps = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E',
12-
'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J',
13-
'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O',
14-
'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T',
15-
'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y',
13+
smalltocaps = {'a': 'A', 'b': 'B', 'c': 'C', 'd': 'D','e': 'E',
14+
'f': 'F', 'g': 'G', 'h': 'H', 'i': 'I','j': 'J',
15+
'k': 'K', 'l': 'L', 'm': 'M', 'n': 'N','o': 'O',
16+
'p': 'P', 'q': 'Q', 'r': 'R', 's': 'S','t': 'T',
17+
'u': 'U', 'v': 'V', 'w': 'W', 'x': 'X','y': 'Y',
1618
'z': 'Z'}
1719

1820
test_assertion(smalltocaps)

src/libasr/codegen/c_utils.h

Lines changed: 152 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,9 +1175,6 @@ class CCPPDSUtils {
11751175
}
11761176

11771177
std::string get_dict_type(ASR::Dict_t* dict_type) {
1178-
if (!ASR::is_a<ASR::Integer_t>(*dict_type->m_key_type)) {
1179-
throw CodeGenError("Only Integer keys supported for now in C-dictionary");
1180-
}
11811178
std::string dict_type_code = ASRUtils::get_type_code((ASR::ttype_t*)dict_type, true);
11821179
if (typecodeToDStype.find(dict_type_code) != typecodeToDStype.end()) {
11831180
return typecodeToDStype[dict_type_code];
@@ -1196,14 +1193,27 @@ class CCPPDSUtils {
11961193
tmp_gen += indent + tab + "bool *present;\n";
11971194
tmp_gen += indent + "};\n\n";
11981195
func_decls += tmp_gen;
1199-
dict_init(dict_type, dict_struct_type, dict_type_code);
1200-
dict_resize(dict_type, dict_struct_type, dict_type_code);
1201-
dict_insert(dict_type, dict_struct_type, dict_type_code);
1202-
dict_get_item(dict_type, dict_struct_type, dict_type_code);
1203-
dict_get_item_with_fallback(dict_type, dict_struct_type, dict_type_code);
1204-
dict_len(dict_type, dict_struct_type, dict_type_code);
1205-
dict_pop(dict_type, dict_struct_type, dict_type_code);
1206-
dict_deepcopy(dict_type, dict_struct_type, dict_type_code);
1196+
generate_compare_funcs(dict_type->m_key_type);
1197+
generate_compare_funcs(dict_type->m_value_type);
1198+
if (ASR::is_a<ASR::Integer_t>(*dict_type->m_key_type)) {
1199+
dict_init(dict_type, dict_struct_type, dict_type_code);
1200+
dict_resize_probing(dict_type, dict_struct_type, dict_type_code);
1201+
dict_insert_probing(dict_type, dict_struct_type, dict_type_code);
1202+
dict_get_item_probing(dict_type, dict_struct_type, dict_type_code);
1203+
dict_get_item_with_fallback_probing(dict_type, dict_struct_type, dict_type_code);
1204+
dict_len(dict_type, dict_struct_type, dict_type_code);
1205+
dict_pop_probing(dict_type, dict_struct_type, dict_type_code);
1206+
dict_deepcopy(dict_type, dict_struct_type, dict_type_code);
1207+
} else {
1208+
dict_init(dict_type, dict_struct_type, dict_type_code);
1209+
dict_resize_naive(dict_type, dict_struct_type, dict_type_code);
1210+
dict_insert_naive(dict_type, dict_struct_type, dict_type_code);
1211+
dict_get_item_naive(dict_type, dict_struct_type, dict_type_code);
1212+
dict_get_item_with_fallback_naive(dict_type, dict_struct_type, dict_type_code);
1213+
dict_len(dict_type, dict_struct_type, dict_type_code);
1214+
dict_pop_naive(dict_type, dict_struct_type, dict_type_code);
1215+
dict_deepcopy(dict_type, dict_struct_type, dict_type_code);
1216+
}
12071217
return dict_struct_type;
12081218
}
12091219

@@ -1231,7 +1241,7 @@ class CCPPDSUtils {
12311241
generated_code += indent + "}\n\n";
12321242
}
12331243

1234-
void dict_resize(ASR::Dict_t *dict_type, std::string dict_struct_type,
1244+
void dict_resize_probing(ASR::Dict_t *dict_type, std::string dict_struct_type,
12351245
std::string dict_type_code) {
12361246
std::string indent(indentation_level * indentation_spaces, ' ');
12371247
std::string tab(indentation_spaces, ' ');
@@ -1268,6 +1278,7 @@ class CCPPDSUtils {
12681278
generated_code += indent + tab + "for(size_t i=0; i<x->capacity/2; i++) {\n";
12691279
generated_code += indent + tab + tab + "if(tmp_p[i]) {\n";
12701280
generated_code += indent + tab + tab + tab + "int j=tmp_key[i]\%x->capacity;\n";
1281+
generated_code += indent + tab + tab + tab + "j=(j+x->capacity)\%x->capacity;\n";
12711282
generated_code += indent + tab + tab + tab + "while(x->present[j]) j=(j+1)\%x->capacity;\n";
12721283
generated_code += indent + tab + tab + tab + \
12731284
"x->key[j] = tmp_key[i]; x->value[j] = tmp_val[i]; x->present[j] = true;\n";
@@ -1276,7 +1287,29 @@ class CCPPDSUtils {
12761287
generated_code += indent + "}\n\n";
12771288
}
12781289

1279-
void dict_insert(ASR::Dict_t *dict_type, std::string dict_struct_type,
1290+
void dict_resize_naive(ASR::Dict_t *dict_type, std::string dict_struct_type,
1291+
std::string dict_type_code) {
1292+
std::string indent(indentation_level * indentation_spaces, ' ');
1293+
std::string tab(indentation_spaces, ' ');
1294+
std::string dict_rez_func = global_scope->get_unique_name("dict_resize_" + dict_type_code);
1295+
typecodeToDSfuncs[dict_type_code]["dict_resize"] = dict_rez_func;
1296+
std::string signature = "void " + dict_rez_func + "(" + dict_struct_type + "* x)";
1297+
func_decls += indent + "inline " + signature + ";\n";
1298+
signature = indent + signature;
1299+
std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type);
1300+
std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type);
1301+
generated_code += indent + signature + " {\n";
1302+
generated_code += indent + tab + "x->capacity = 2*x->capacity + 1;\n";
1303+
generated_code += indent + tab + "x->key = (" + key + "*) " +
1304+
"realloc(x->key, x->capacity * sizeof(" + key + "));\n";
1305+
generated_code += indent + tab + "x->value = (" + val + "*) " +
1306+
"realloc(x->value, x->capacity * sizeof(" + val + "));\n";
1307+
generated_code += indent + tab + "x->present = (bool*) " +
1308+
"realloc(x->present, x->capacity * sizeof(bool));\n";
1309+
generated_code += indent + "}\n\n";
1310+
}
1311+
1312+
void dict_insert_probing(ASR::Dict_t *dict_type, std::string dict_struct_type,
12801313
std::string dict_type_code) {
12811314
std::string indent(indentation_level * indentation_spaces, ' ');
12821315
std::string tab(indentation_spaces, ' ');
@@ -1291,18 +1324,48 @@ class CCPPDSUtils {
12911324
signature = indent + signature;
12921325
generated_code += indent + signature + " {\n";
12931326
generated_code += indent + tab + "int j=k\%x->capacity; int c = 0;\n";
1327+
generated_code += indent + tab + "j=(j+x->capacity)\%x->capacity;\n";
12941328
generated_code += indent + tab + "while(c < x->capacity && x->present[j] && x->key[j]!=k) j=(j+1)\%x->capacity, c++;\n";
12951329
generated_code += indent + tab + "if (c == x->capacity) {\n";
12961330
generated_code += indent + tab + tab + dict_rz + "(x);\n";
1297-
generated_code += indent + tab + tab + "j=k\%x->capacity;\n";
1331+
generated_code += indent + tab + tab + "j=k\%x->capacity; j=(j+x->capacity)\%x->capacity;\n";
12981332
generated_code += indent + tab + tab + "while(x->present[j]) j=(j+1)\%x->capacity;\n";
12991333
generated_code += indent + tab + "}\n";
13001334
generated_code += indent + tab + \
13011335
"x->key[j] = k; x->value[j] = v; x->present[j] = true;\n";
13021336
generated_code += indent + "}\n\n";
13031337
}
13041338

1305-
void dict_get_item(ASR::Dict_t *dict_type, std::string dict_struct_type,
1339+
void dict_insert_naive(ASR::Dict_t *dict_type, std::string dict_struct_type,
1340+
std::string dict_type_code) {
1341+
std::string indent(indentation_level * indentation_spaces, ' ');
1342+
std::string tab(indentation_spaces, ' ');
1343+
std::string dict_in_func = global_scope->get_unique_name("dict_insert_" + dict_type_code);
1344+
typecodeToDSfuncs[dict_type_code]["dict_insert"] = dict_in_func;
1345+
std::string dict_rz = typecodeToDSfuncs[dict_type_code]["dict_resize"];
1346+
std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type);
1347+
std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type);
1348+
std::string signature = "void " + dict_in_func + "(" + dict_struct_type + "* x, " +\
1349+
key + " k," + val + " v)" ;
1350+
func_decls += indent + "inline " + signature + ";\n";
1351+
signature = indent + signature;
1352+
generated_code += indent + signature + " {\n";
1353+
std::string key_cmp_func = get_compare_func(dict_type->m_key_type);
1354+
std::string key_cmp = key_cmp_func + "(x->key[c], k)";
1355+
generated_code += indent + tab + "int c = 0;\n";
1356+
generated_code += indent + tab + "while(c < x->capacity && x->present[c] && !" + key_cmp + ") c++;\n";
1357+
generated_code += indent + tab + "if (c == x->capacity) {\n";
1358+
generated_code += indent + tab + tab + dict_rz + "(x);\n";
1359+
generated_code += indent + tab + "}\n";
1360+
std::string key_deep_copy = get_deepcopy(dict_type->m_key_type, "k", "x->key[c]");
1361+
std::string val_deep_copy = get_deepcopy(dict_type->m_value_type, "v", "x->value[c]");
1362+
generated_code += indent + tab + key_deep_copy + "\n";
1363+
generated_code += indent + tab + val_deep_copy + "\n";
1364+
generated_code += indent + tab + "x->present[c] = true;\n";
1365+
generated_code += indent + "}\n\n";
1366+
}
1367+
1368+
void dict_get_item_probing(ASR::Dict_t *dict_type, std::string dict_struct_type,
13061369
std::string dict_type_code) {
13071370
std::string indent(indentation_level * indentation_spaces, ' ');
13081371
std::string tab(indentation_spaces, ' ');
@@ -1316,14 +1379,38 @@ class CCPPDSUtils {
13161379
signature = indent + signature;
13171380
generated_code += indent + signature + " {\n";
13181381
generated_code += indent + tab + "int j=k\%x->capacity, c = 0;\n";
1382+
generated_code += indent + tab + "j=(j+x->capacity)\%x->capacity;\n";
13191383
generated_code += indent + tab + "while(c<x->capacity && x->present[j] && !(x->key[j] == k)) j=(j+1)\%x->capacity, c++;\n";
13201384
generated_code += indent + tab + "if (x->present[j] && x->key[j] == k) return x->value[j];\n";
13211385
generated_code += indent + tab + "printf(\"Key not found\\n\");\n";
13221386
generated_code += indent + tab + "exit(1);\n";
13231387
generated_code += indent + "}\n\n";
13241388
}
13251389

1326-
void dict_get_item_with_fallback(ASR::Dict_t *dict_type, std::string dict_struct_type,
1390+
void dict_get_item_naive(ASR::Dict_t *dict_type, std::string dict_struct_type,
1391+
std::string dict_type_code) {
1392+
std::string indent(indentation_level * indentation_spaces, ' ');
1393+
std::string tab(indentation_spaces, ' ');
1394+
std::string dict_get_func = global_scope->get_unique_name("dict_get_item_" + dict_type_code);
1395+
typecodeToDSfuncs[dict_type_code]["dict_get"] = dict_get_func;
1396+
std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type);
1397+
std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type);
1398+
std::string signature = val + " " + dict_get_func + "(" + dict_struct_type + "* x, " +\
1399+
key + " k)" ;
1400+
func_decls += indent + "inline " + signature + ";\n";
1401+
signature = indent + signature;
1402+
generated_code += indent + signature + " {\n";
1403+
std::string key_cmp_func = get_compare_func(dict_type->m_key_type);
1404+
std::string key_cmp = key_cmp_func + "(x->key[i], k)";
1405+
generated_code += indent + tab + "for (int i=0; i<x->capacity; i++) {\n";
1406+
generated_code += indent + tab + tab + "if (x->present[i] && "+ key_cmp + ") return x->value[i];\n";
1407+
generated_code += indent + tab + "}\n";
1408+
generated_code += indent + tab + "printf(\"Key not found\\n\");\n";
1409+
generated_code += indent + tab + "exit(1);\n";
1410+
generated_code += indent + "}\n\n";
1411+
}
1412+
1413+
void dict_get_item_with_fallback_probing(ASR::Dict_t *dict_type, std::string dict_struct_type,
13271414
std::string dict_type_code) {
13281415
std::string indent(indentation_level * indentation_spaces, ' ');
13291416
std::string tab(indentation_spaces, ' ');
@@ -1337,12 +1424,35 @@ class CCPPDSUtils {
13371424
signature = indent + signature;
13381425
generated_code += indent + signature + " {\n";
13391426
generated_code += indent + tab + "int j=k\%x->capacity, c = 0;\n";
1427+
generated_code += indent + tab + "j=(j+x->capacity)\%x->capacity;\n";
13401428
generated_code += indent + tab + "while(c<x->capacity && x->present[j] && !(x->key[j] == k)) j=(j+1)\%x->capacity, c++;\n";
13411429
generated_code += indent + tab + "if (x->present[j] && x->key[j] == k) return x->value[j];\n";
13421430
generated_code += indent + tab + "return dv;\n";
13431431
generated_code += indent + "}\n\n";
13441432
}
13451433

1434+
void dict_get_item_with_fallback_naive(ASR::Dict_t *dict_type, std::string dict_struct_type,
1435+
std::string dict_type_code) {
1436+
std::string indent(indentation_level * indentation_spaces, ' ');
1437+
std::string tab(indentation_spaces, ' ');
1438+
std::string dict_get_func = global_scope->get_unique_name("dict_get_item_fb_" + dict_type_code);
1439+
typecodeToDSfuncs[dict_type_code]["dict_get_fb"] = dict_get_func;
1440+
std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type);
1441+
std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type);
1442+
std::string signature = val + " " + dict_get_func + "(" + dict_struct_type + "* x, " +\
1443+
key + " k, " + val + " dv)";
1444+
func_decls += indent + "inline " + signature + ";\n";
1445+
signature = indent + signature;
1446+
generated_code += indent + signature + " {\n";
1447+
std::string key_cmp_func = get_compare_func(dict_type->m_key_type);
1448+
std::string key_cmp = key_cmp_func + "(x->key[i], k)";
1449+
generated_code += indent + tab + "for (int i=0; i<x->capacity; i++) {\n";
1450+
generated_code += indent + tab + tab + "if (x->present[i] && "+ key_cmp + ") return x->value[i];\n";
1451+
generated_code += indent + tab + "}\n";
1452+
generated_code += indent + tab + "return dv;\n";
1453+
generated_code += indent + "}\n\n";
1454+
}
1455+
13461456
void dict_len(ASR::Dict_t *dict_type, std::string dict_struct_type,
13471457
std::string dict_type_code) {
13481458
std::string indent(indentation_level * indentation_spaces, ' ');
@@ -1361,7 +1471,7 @@ class CCPPDSUtils {
13611471
generated_code += indent + "}\n\n";
13621472
}
13631473

1364-
void dict_pop(ASR::Dict_t *dict_type, std::string dict_struct_type,
1474+
void dict_pop_probing(ASR::Dict_t *dict_type, std::string dict_struct_type,
13651475
std::string dict_type_code) {
13661476
std::string indent(indentation_level * indentation_spaces, ' ');
13671477
std::string tab(indentation_spaces, ' ');
@@ -1374,6 +1484,7 @@ class CCPPDSUtils {
13741484
signature = indent + signature;
13751485
generated_code += indent + signature + " {\n";
13761486
generated_code += indent + tab + "int j = k\%x->capacity;\n";
1487+
generated_code += indent + tab + "j=(j+x->capacity)\%x->capacity;\n";
13771488
generated_code += indent + tab + "for(int i=0; i < x->capacity; i++) {\n";
13781489
generated_code += indent + tab + tab + "if (x->present[j] && x->key[j] == k) {\n";
13791490
generated_code += indent + tab + tab + tab + "x->present[j] = false;\n";
@@ -1385,6 +1496,30 @@ class CCPPDSUtils {
13851496
generated_code += indent + "}\n\n";
13861497
}
13871498

1499+
void dict_pop_naive(ASR::Dict_t *dict_type, std::string dict_struct_type,
1500+
std::string dict_type_code) {
1501+
std::string indent(indentation_level * indentation_spaces, ' ');
1502+
std::string tab(indentation_spaces, ' ');
1503+
std::string dict_pop_func = global_scope->get_unique_name("dict_pop_" + dict_type_code);
1504+
typecodeToDSfuncs[dict_type_code]["dict_pop"] = dict_pop_func;
1505+
std::string key = CUtils::get_c_type_from_ttype_t(dict_type->m_key_type);
1506+
std::string val = CUtils::get_c_type_from_ttype_t(dict_type->m_value_type);
1507+
std::string signature = val + " " + dict_pop_func + "(" + dict_struct_type + "* x, " + key + " k)";
1508+
func_decls += indent + "inline " + signature + ";\n";
1509+
signature = indent + signature;
1510+
generated_code += indent + signature + " {\n";
1511+
std::string key_cmp_func = get_compare_func(dict_type->m_key_type);
1512+
std::string key_cmp = key_cmp_func + "(x->key[i], k)";
1513+
generated_code += indent + tab + "for(int i=0; i < x->capacity; i++) {\n";
1514+
generated_code += indent + tab + tab + "if (x->present[i] && "+ key_cmp + ") {\n";
1515+
generated_code += indent + tab + tab + tab + "x->present[i] = false;\n";
1516+
generated_code += indent + tab + tab + tab + "return x->value[i];\n";
1517+
generated_code += indent + tab + tab + "}\n";
1518+
generated_code += indent + tab + "}\n";
1519+
generated_code += indent + tab + "printf(\"Key not found\\n\"); exit(1);\n";
1520+
generated_code += indent + "}\n\n";
1521+
}
1522+
13881523
void dict_deepcopy(ASR::Dict_t *dict_type, std::string dict_struct_type,
13891524
std::string dict_type_code) {
13901525
std::string indent(indentation_level * indentation_spaces, ' ');

0 commit comments

Comments
 (0)