Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

khash example in gh-pages documentation uses non-existing variable #130

Open
rofl0r opened this issue Jun 21, 2019 · 7 comments
Open

khash example in gh-pages documentation uses non-existing variable #130

rofl0r opened this issue Jun 21, 2019 · 7 comments

Comments

@rofl0r
Copy link

rofl0r commented Jun 21, 2019

the example uses if(!ret) even though ret isn't declared. i assume k is meant.

@rofl0r rofl0r changed the title kash example in gh-pages documentation uses non-existing variable khash example in gh-pages documentation uses non-existing variable Jun 21, 2019
@yifangt
Copy link

yifangt commented Dec 5, 2019

I had the same problem.
Could not figure out the fix due to the huge macro beyond my experience.
Is there a fix of that please? Thanks a lot.

@selavy
Copy link

selavy commented Dec 5, 2019

It should be absent in example 1. If you look at the documentation for kh_put():

/*! @function
  @abstract     Insert a key to the hash table.
  @param  name  Name of the hash table [symbol]
  @param  h     Pointer to the hash table [khash_t(name)*]
  @param  k     Key [type of keys]
  @param  r     Extra return code: -1 if the operation failed;
                0 if the key is present in the hash table;
                1 if the bucket is empty (never used); 2 if the element in
				the bucket has been deleted [int*]
  @return       Iterator to the inserted element [khint_t]
 */
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)

absent == 0 tells you that the key was already present in the table.

Honestly though, line 8 should be deleted. Calling kh_del() would invalidate the k iterator so calling kh_value() with it would then be invalid.

@yifangt
Copy link

yifangt commented Dec 5, 2019

@selavy Thanks!
To follow the original logic of the code, the variable ret should be absent, i.e. if (!absent) right?

@selavy
Copy link

selavy commented Dec 6, 2019

@yifangt

The original logic of the code doesn't make sense. Hopefully this code snippet is explains why:

#include <assert.h>
#include <stdbool.h>
#include "khash.h"

enum {
    ERROR           = -1,
    ELEMENT_PRESENT = 0,
    EMPTY           = 1,
    TOMBSTONE       = 2,
};

KHASH_MAP_INIT_INT(m32, char)
int main(int argc, char **argv)
{
    int absent;
    int is_missing;
    khint_t k;

    // initialize the table
    khash_t(m32) *h = kh_init(m32);

    // insert a key of 5 (N.B. the value is NOT set)
    k = kh_put(m32, h, 5, &absent);
    assert(kh_size(h) == 1);
    assert(absent != ELEMENT_PRESENT);
    assert(absent == EMPTY);

    // delete the key we just inserted
    kh_del(m32, h, k);
    assert(kh_size(h) == 0);
    assert(kh_exist(h, k) == false); // iterator is invalid now
    assert(kh_get(m32, h, 5) == kh_end(h));

    // because kh_exist(h, k) == false, the line below is a bug:
    // kh_value(h, k) = 10;

    // re-insert a key of 5 (N.B. the value is still not set)
    k = kh_put(m32, h, 5, &absent);
    assert(kh_size(h) == 1);
    assert(absent == TOMBSTONE); // tombstone because we deleted the key
    assert(kh_get(m32, h, 5) != kh_end(h));

    // now set the value
    kh_value(h, k) = 10;
    assert(kh_value(h, kh_get(m32, h, 5)) == 10);

    return 0;
}

@yifangt
Copy link

yifangt commented Dec 10, 2019

Thanks a lot!
I need more time to understand the huge macro, especially the logic wrapped inside.

@selavy
Copy link

selavy commented Dec 10, 2019

I would recommend reading through the documentation that is in the file:

klib/khash.h

Lines 428 to 549 in f719aad

/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)

@rofl0r
Copy link
Author

rofl0r commented Dec 11, 2019

I would recommend reading through the documentation that is in the file:

i would recommend opening a PR fixing the docs, but then it looks like this repo is unmaintained anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants