I am relatively new to C, although I have been developing with other languages for an extended period of time. In an attempt to "Learn by doing", whilst working through a coursera course on C & C++ I decided to challenge myself with both by writing a wrapper for an existing project, which would translate to what I would eventually be using them for in my real world application of them.
I am building a C interface for a C++ implementation of Google Sparse Hash Map, using a guide on C interfaces / wrapping (here), but seem to be having issues with either data not inserting, or not being able to read the data once inserted?
This is what I have.
The C++ Object
sparsehashmap.cpp
#include "sparsehashmap.h"
#include<string>
SparseHashMap::SparseHashMap(){_shash.set_deleted_key("");}
void SparseHashMap::insert(const char* arg1, const char* arg2)
{
_shash[arg1] = arg2;
}
const char* SparseHashMap::read(const char* key)
{
return _shash[key];
}
int SparseHashMap::exists(const char* key)
{
if (_shash.find(key) == _shash.end())
{
return false;
}
else
{
return true;
}
}
void SparseHashMap::remove(const char* key)
{
_shash.erase(key);
}
int SparseHashMap::length()
{
return (int) _shash.size();
}
void SparseHashMap::flush()
{
_shash.clear();
}
sparsehashmap.h
#ifndef __CPPSPARSEHASH__
#define __CPPSPARSEHASH__
#include <iostream>
#include <sparsehash/sparse_hash_map> //https://github.com/sparsehash/sparsehash
typedef google::sparse_hash_map<const char*, const char*> _SPARSEHASH;
class SparseHashMap
{
private:
_SPARSEHASH _shash;
public:
SparseHashMap();
void insert(const char* arg1, const char* arg2);
const char* read(const char* key);
int exists(const char* key);
void remove(const char* key);
int length();
void flush();
};
#endif // __CPPSPARSEHASH__
The C Wrapper
sparse.h
#ifndef __FOSPARSE_H__
#define __FOSPARSE_H__
#ifdef __cplusplus
extern "C" {
#endif
struct CSparseHashMap;
typedef struct CSparseHashMap _SparseHashMap;
_SparseHashMap *sparsehashmap_create();
void sparsehashmap_destroy(_SparseHashMap *shm);
void sparsehashmap_insert (_SparseHashMap *shm, const char* arg1, const char* arg2);
const char* sparsehashmap_read (_SparseHashMap *shm, const char* key);
int sparsehashmap_exists (_SparseHashMap *shm, const char* key);
void sparsehashmap_remove (_SparseHashMap *shm, const char* key);
int sparsehashmap_length (_SparseHashMap *shm);
void sparsehashmap_flush (_SparseHashMap *shm);
#ifdef __cplusplus
}
#endif
#endif
sparse.cpp
#include <stdlib.h>
#include "sparse.h"
#include "sparsehashmap.h"
struct CSparseHashMap {
void *obj;
};
_SparseHashMap *sparsehashmap_create()
{
_SparseHashMap *shm;
SparseHashMap *obj;
shm = (__typeof__(shm))malloc(sizeof(*shm));
obj = new SparseHashMap();
shm->obj = obj;
return shm;
}
void sparsehashmap_destroy(_SparseHashMap *shm)
{
if (shm == NULL)
return;
delete static_cast<SparseHashMap *>(shm->obj);
free(shm);
}
void sparsehashmap_insert(_SparseHashMap *shm, const char* arg1, const char* arg2)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->insert(arg1, arg2);
}
const char* sparsehashmap_read(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->read(key);
}
int sparsehashmap_exists(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->exists(key);
}
void sparsehashmap_remove(_SparseHashMap *shm, const char* key)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->remove(key);
}
int sparsehashmap_length(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return 0;
obj = static_cast<SparseHashMap *>(shm->obj);
return obj->length();
}
void sparsehashmap_flush(_SparseHashMap *shm)
{
SparseHashMap *obj;
if (shm == NULL)
return;
obj = static_cast<SparseHashMap *>(shm->obj);
obj->flush();
}
The Test
main.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "sparse.h"
#define MAXCHAR 256
int main(int argc, char* argv[])
{
// Create Pointer to Sparsehashmap object
_SparseHashMap *fshm = sparsehashmap_create();
/*
Open File specified in command line argument <argv[1]>
and initialise array pointer to hold the line data
*/
FILE *fp;
char row[MAXCHAR];
int ct = 0;
fp = fopen(argv[1], "r");
/*
Loop through the file, split the row using a single space
as a delimeter, and insert as <key> => <value> into the
sparsehashmap
*/
while (feof(fp) != true)
{
char key[MAXCHAR], value[MAXCHAR];
fgets(row, MAXCHAR, fp);
sscanf(row, "%s %s", key, value);
// if( (ct % 100) == 0 )
// printf("Key: %s\tValue: %s\n", key, value);
sparsehashmap_insert(fshm, key, value);
ct++;
}
// close the file as it is no longer needed.
fclose(fp);
// Print the total number of times the while loop ran
printf("%d Total entries.\n", ct);
// Print the length of the Sparsehashmap
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Read, Exists and Remove Examples
*/
printf("C SparseHashMap: _SparseHashMap[\"63-5039337\"] = %s\n", sparsehashmap_read(fshm, "63-5039337"));
printf("C SparseHashMap: _SparseHashMap[\"26-8663826\"] = %s\n", sparsehashmap_read(fshm, "26-8663826"));
printf("C SparseHashMap: _SparseHashMap[\"87-9801138\"] = %s\n", sparsehashmap_read(fshm, "87-9801138"));
printf("C SparseHashMap: Key Exists [\"15-8895492\"] = %d\n", sparsehashmap_exists(fshm, "15-8895492"));
printf("C SparseHashMap: Key Exists [\"22-4942175\"] = %d\n", sparsehashmap_exists(fshm, "22-4942175"));
printf("C SparseHashMap: Remove Key From Hashmap...\n");
printf("C SparseHashMap: Remove Key From Hashmap [\"63-5039337\"]\n");
sparsehashmap_remove(fshm, "63-5039337");
printf("C SparseHashMap: Remove Key From Hashmap [\"20-6892893\"]\n");
sparsehashmap_remove(fshm, "20-6892893");
printf("C SparseHashMap: Remove Key From Hashmap [\"58-8150180\"]\n");
sparsehashmap_remove(fshm, "58-8150180");
printf("C SparseHashMap: Length of Hashmap = %d\n", sparsehashmap_length(fshm));
/*
Destroy the Sparsehashmap to free its
memory allocation.
*/
printf("C SparseHashMap: Destroy Hashmap\n");
sparsehashmap_destroy(fshm);
printf("C SparseHashMap: Freed");
return 0;
}
I have created a gist of the data that I am inserting and querying, which can be found here.
Once built, I run it against the file of mock data, but of the file of 2000 test entries, these are the results I get
2001 Total entries. /* times file is looped with fgets() */
C SparseHashMap: Length of Hashmap = 1 /* Size of the hashmap */
C SparseHashMap: _SparseHashMap["63-5039337"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["26-8663826"] = (null) /* Read Function Response */
C SparseHashMap: _SparseHashMap["87-9801138"] = (null) /* Read Function Response */
C SparseHashMap: Key Exists ["15-8895492"] = 0
C SparseHashMap: Key Exists ["22-4942175"] = 0
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 3 /* Size of the hashmap */
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed%
The size of the Hash Map starts at one (after apparently inserting 2000 entries), it is unable to read any keys from the input data, and then after it performs a number of removals, the length jumps to three?
I understand that the guide I am working from is a bit more basic than working with a hash map, but was wondering if anyone could point me to where I am going wrong with this? and how I should be looking at modifying it to have the operations working as expected?
Any guidance would be greatly appreciated.
======== EDIT ========
The issue seemed to be mapping pointers to pointers. After amending the *.cpp
files to take / return std::string
, and performing the relevant conversions before passing from the C instructions the interface began working as intended
./run MOCK_DATA.txt
2001 Total entries.
C SparseHashMap: Length of Hashmap = 2000
C SparseHashMap: _SparseHashMap["63-5039337"] = {"id":1,"first_name":"Ilario","last_name":"Thickins","email":"ithickins0@nbcnews.com","gender":"Male","ip_address":"54.113.8.103"}
C SparseHashMap: _SparseHashMap["26-8663826"] = {"id":35,"first_name":"Mignonne","last_name":"Oakden","email":"moakdeny@ifeng.com","gender":"Female","ip_address":"41.14.68.148"}
C SparseHashMap: _SparseHashMap["87-9801138"] = {"id":1989,"first_name":"Mavis","last_name":"Collingwood","email":"mcollingwoodrg@google.it","gender":"Female","ip_address":"56.70.97.65"}
C SparseHashMap: Key Exists ["15-8895492"] = 1
C SparseHashMap: Key Exists ["22-4942175"] = 1
C SparseHashMap: Remove Key From Hashmap ["63-5039337"]
C SparseHashMap: Remove Key From Hashmap ["20-6892893"]
C SparseHashMap: Remove Key From Hashmap ["58-8150180"]
C SparseHashMap: Length of Hashmap = 1997
C SparseHashMap: Destroy Hashmap
C SparseHashMap: Freed