sdskv-client.hpp 57.9 KB
Newer Older
1 2 3
#ifndef __SDSKV_CLIENT_HPP
#define __SDSKV_CLIENT_HPP

Matthieu Dorier's avatar
Matthieu Dorier committed
4
#include <type_traits>
5 6 7 8
#include <stdexcept>
#include <vector>
#include <string>
#include <sdskv-client.h>
Matthieu Dorier's avatar
Matthieu Dorier committed
9
#include <sdskv-common.hpp>
10 11 12 13 14 15

#define _CHECK_RET(__ret) \
        if(__ret != SDSKV_SUCCESS) throw exception(__ret)

namespace sdskv {

Matthieu Dorier's avatar
Matthieu Dorier committed
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

// The functions bellow (object_size, object_data, object_resize) are defined
// for std::string and std::vector<X> when X is a standard layout type. They
// are used in place of x.size(), x.data(), and x.resize() to allow better
// genericity. Also if a user wants to add support for another type, overloading
// these functions is the way to go: the object_data() function must return a
// void* pointer to where data from an object can be accessed directory.
// object_size() functions must return the size (in bytes) of the underlying
// buffer. object_resize must be able to resize the object.

template<typename T, std::enable_if_t<std::is_standard_layout<T>::value, int> = 0>
inline size_t object_size(const std::vector<T>& v) {
    return sizeof(v[0])*v.size();
}

inline size_t object_size(const std::string& s) {
    return s.size();
}

template<typename T, std::enable_if_t<std::is_standard_layout<T>::value, int> = 0>
inline void* object_data(std::vector<T>& v) {
    return (void*)v.data();
}

inline void* object_data(std::string& s) {
    return (void*)s.data();
}

template<typename T, std::enable_if_t<std::is_standard_layout<T>::value, int> = 0>
inline const void* object_data(const std::vector<T>& v) {
    return (const void*)v.data();
}

inline const void* object_data(const std::string& s) {
    return (const void*)s.data();
}

template<typename T, std::enable_if_t<std::is_standard_layout<T>::value, int> = 0>
inline void object_resize(std::vector<T>& v, size_t new_size) {
    v.resize(new_size);
}

Matthieu Dorier's avatar
Matthieu Dorier committed
58
inline void object_resize(std::string& s, size_t new_size) {
Matthieu Dorier's avatar
Matthieu Dorier committed
59 60 61
    s.resize(new_size);
}

62 63 64
class provider_handle;
class database;

Matthieu Dorier's avatar
Matthieu Dorier committed
65 66 67
/**
 * @brief The sdskv::client class is the C++ equivalent of a C sdskv_client_t.
 */
68 69 70 71 72 73 74 75
class client {

    friend class provider_handle;

    margo_instance_id m_mid = MARGO_INSTANCE_NULL;
    sdskv_client_t m_client = SDSKV_CLIENT_NULL;
    bool           m_owns_client = true;

Matthieu Dorier's avatar
Matthieu Dorier committed
76

77 78
    public:

Matthieu Dorier's avatar
Matthieu Dorier committed
79 80 81
    /**
     * @brief Default constructor. Will create an invalid client.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
82 83
    client() = default;

Matthieu Dorier's avatar
Matthieu Dorier committed
84 85 86 87 88
    /**
     * @brief Main constructor. Creates a valid client from a Margo instance.
     *
     * @param mid Margo instance.
     */
89 90
    client(margo_instance_id mid)
    : m_mid(mid) {
Matthieu Dorier's avatar
Matthieu Dorier committed
91
        sdskv_client_init(mid, &m_client);
92 93
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
94 95 96 97 98 99 100 101
    /**
     * @brief Creates a valid client from an existing sdskv_client_t.
     *
     * @param mid Margo instance.
     * @param c Existing C client.
     * @param transfer_ownership Whether this client instance should take ownership
     * and free the underlying handle in its destructor.
     */
102 103 104 105 106
    client(margo_instance_id mid, sdskv_client_t c, bool transfer_ownership=false)
    : m_mid(mid)
    , m_client(c)
    , m_owns_client(transfer_ownership) {}

Matthieu Dorier's avatar
Matthieu Dorier committed
107 108 109
    /**
     * @brief Deleted copy constructor.
     */
110 111
    client(const client& c) = delete;

Matthieu Dorier's avatar
Matthieu Dorier committed
112 113 114
    /**
     * @brief Move constructor, will invalidate the client that is moved from.
     */
115 116 117
    client(client&& c)
    : m_mid(c.m_mid)
    , m_client(c.m_client)
Matthieu Dorier's avatar
Matthieu Dorier committed
118
    , m_owns_client(c.m_owns_client) {
119 120 121
        c.m_client = SDSKV_CLIENT_NULL;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
122 123 124
    /**
     * @brief Deleted copy-assignment operator.
     */
125 126
    client& operator=(const client& c) = delete;

Matthieu Dorier's avatar
Matthieu Dorier committed
127 128 129
    /**
     * @brief Move assignment operator, will invalidate the client that is moved from.
     */
130 131 132 133 134 135 136 137 138 139 140 141 142
    client& operator=(client&& c) {
        if(this == &c) return *this;
        if(m_client && m_owns_client) {
            sdskv_client_finalize(m_client);
        }
        m_mid           = c.m_mid;
        m_client        = c.m_client;
        m_owns_client   = c.m_owns_client;
        c.m_client      = SDSKV_CLIENT_NULL;
        c.m_owns_client = true;
        return *this;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
143 144 145 146
    /**
     * @brief Destructor. If this instance owns the underlying C handle, this handle
     * will be destroyed.
     */
147
    ~client() {
Matthieu Dorier's avatar
Matthieu Dorier committed
148
        if(m_owns_client && m_client)
149 150 151
            sdskv_client_finalize(m_client);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
152 153 154
    /**
     * @brief Cast operator to sdskv_client_t.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
155 156 157 158
    operator sdskv_client_t() const {
        return m_client;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
159 160 161 162 163
    /**
     * @brief Cast to bool.
     *
     * @return true if the client is valid, false otherwise.
     */
164 165 166 167
    operator bool() const {
        return m_client != SDSKV_CLIENT_NULL;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
168 169 170 171 172 173 174 175
    /**
     * @brief Open a database held by a given provider.
     *
     * @param ph Provider handle.
     * @param db_name Database name.
     *
     * @return database instance.
     */
176 177
    database open(const provider_handle& ph, const std::string& db_name) const;

Matthieu Dorier's avatar
Matthieu Dorier committed
178 179 180 181 182 183 184
    /**
     * @brief Open all the databases held by a given provider.
     *
     * @param ph Provider handle.
     *
     * @return Vector of database instances.
     */
185 186 187 188 189 190
    std::vector<database> open(const provider_handle& ph) const;

    //////////////////////////
    // PUT methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
191 192 193 194 195 196 197 198 199
    /**
     * @brief Equivalent of sdskv_put.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key in bytes.
     * @param value Value.
     * @param vsize Size of the value in bytes.
     */
200
    void put(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
201 202
             const void *key, hg_size_t ksize,
             const void *value, hg_size_t vsize) const;
203

Matthieu Dorier's avatar
Matthieu Dorier committed
204 205 206 207 208 209 210 211 212 213 214
    /**
     * @brief Put method taking templated keys and values. This method
     * is meant to work with std::vector<X> and std::string. X must be
     * a standard layout type.
     *
     * @tparam K std::vector<char> or std::string.
     * @tparam V std::vector<char> or std::string.
     * @param db Database instance.
     * @param key Key.
     * @param value Value.
     */
215
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
216
    inline void put(const database& db,
217
             const K& key, const V& value) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
218
        put(db, object_data(key), object_size(key), object_data(value), object_size(value));
219 220
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
221 222 223 224
    //////////////////////////
    // PUT_MULTI methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
225 226 227 228 229 230 231 232 233 234
    /**
     * @brief Equivalent to sdskv_put_multi.
     *
     * @param db Database instance.
     * @param count Number of key/val pairs.
     * @param keys Array of keys.
     * @param ksizes Array of key sizes.
     * @param values Array of values.
     * @param vsizes Array of value sizes.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
235
    void put_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
236 237
             hg_size_t count, const void* const* keys, const hg_size_t* ksizes,
             const void* const* values, const hg_size_t *vsizes) const;
238 239


Matthieu Dorier's avatar
Matthieu Dorier committed
240 241 242 243 244 245 246 247 248
    /**
     * @brief Version of put taking std::vectors instead of arrays of pointers.
     *
     * @param db Database instance.
     * @param keys Vector of pointers to keys.
     * @param ksizes Vector of key sizes.
     * @param values Vector of pointers to values.
     * @param vsizes Vector of value sizes.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
249
    inline void put_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
250 251
             const std::vector<const void*>& keys, const std::vector<hg_size_t>& ksizes,
             const std::vector<const void*>& values, const  std::vector<hg_size_t>& vsizes) const {
252 253 254 255 256
        if(keys.size() != ksizes.size()
        || keys.size() != values.size()
        || keys.size() != vsizes.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
257
        put_multi(db, keys.size(), keys.data(),  ksizes.data(), values.data(), vsizes.data());
258 259
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
260 261 262 263 264 265 266 267 268 269
    /**
     * @brief Templated put method. Meant to work with std::vector<X> and std::string types.
     * X must be a standard layout  type.
     *
     * @tparam K std::vector<char> or std::string.
     * @tparam V std::vector<char> or std::string.
     * @param db Database instance.
     * @param keys Vector of keys.
     * @param values Vector of values.
     */
270
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
271
    inline void put_multi(const database& db,
272 273 274 275 276
             const std::vector<K>& keys, const std::vector<V>& values) {
        if(keys.size() != values.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
277 278 279
        std::vector<const void*> vdata; vdata.reserve(values.size());
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.size());
280
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
281 282
            ksizes.push_back(object_size(k));
            kdata.push_back(object_data(k));
283 284
        }
        for(const auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
285 286
            vsizes.push_back(object_size(v));
            vdata.push_back(object_data(v));
287
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
288
        put_multi(db, kdata, ksizes, vdata, vsizes);
289 290
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
291 292 293 294 295 296 297 298 299 300 301 302 303
    /**
     * @brief Put method taking iterators to templated key and value types,
     * meant to work with keys and values of type std::vector<X> and std::string.
     * X must be a standard layout type.
     *
     * @tparam IK Type of iterator to keys.
     * @tparam IV Type of iterator to values.
     * @param db Database instance.
     * @param kbegin beginning of the iterator to keys.
     * @param kend end of the iterator to keys.
     * @param vbegin beginning of the iterator to values.
     * @param vend end of the iterator to values.
     */
304
    template<typename IK, typename IV>
Matthieu Dorier's avatar
Matthieu Dorier committed
305
    inline void put_multi(const database& db,
306 307
             const IK& kbegin, const IK& kend,
             const IV& vbegin, const IV& vend) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
308
        hg_size_t count = std::distance(kbegin, kend);
309 310 311 312 313
        if(count != std::distance(vbegin, vend)) {
            throw std::length_error("Provided iterators should point to the same number of objects");
        }
        std::vector<const void*> kdata; kdata.reserve(count);
        std::vector<const void*> vdata; vdata.reserve(count);
Matthieu Dorier's avatar
Matthieu Dorier committed
314 315
        std::vector<hg_size_t> ksizes; ksizes.reserve(count);
        std::vector<hg_size_t> vsizes; vsizes.reserve(count);
316
        for(auto it = kbegin; it != kend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
317
            ksizes.push_back(object_size(*it));
318
            kdata.push_back(object_data(*it));
319 320
        }
        for(auto it = vbegin; it != vend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
321
            vsizes.push_back(object_size(*it));
322
            vdata.push_back(object_data(*it));
323
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
324
        put_multi(db, kdata, ksizes, vdata, vsizes);
325 326
    }

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
    //////////////////////////
    // PUT_PACKED methods
    //////////////////////////

    /**
     * @brief Equivalent to sdskv_put_packed.
     *
     * @param db Database instance.
     * @param count Number of key/val pairs.
     * @param keys Buffer of keys.
     * @param ksizes Array of key sizes.
     * @param values Buffer of values.
     * @param vsizes Array of value sizes.
     */
    void put_packed(const database& db,
             hg_size_t count, const void* keys, const hg_size_t* ksizes,
             const void* values, const hg_size_t *vsizes) const;

    /**
     * @brief Version of put taking std::strings instead of pointers.
     *
     * @param db Database instance.
     * @param keys Vector of pointers to keys.
     * @param ksizes Vector of key sizes.
     * @param values Vector of pointers to values.
     * @param vsizes Vector of value sizes.
     */
    inline void put_packed(const database& db,
             const std::string& packed_keys, const std::vector<hg_size_t>& ksizes,
             const std::string& packed_values, const  std::vector<hg_size_t>& vsizes) const {
        put_packed(db, ksizes.size(), packed_keys.data(),  ksizes.data(), packed_values.data(), vsizes.data());
    }

360 361 362 363
    //////////////////////////
    // EXISTS methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
364 365 366 367 368 369 370 371 372
    /**
     * @brief Equivalent of sdskv_exists.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key.
     *
     * @return true if key exists, false otherwise.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
373
    bool exists(const database& db, const void* key, hg_size_t ksize) const;
374

Matthieu Dorier's avatar
Matthieu Dorier committed
375 376 377 378 379 380 381 382 383 384
    /**
     * @brief Templated version of exists method, meant to work with
     * std::string and std::vector<X>. X must be a standard layout type.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param key Key.
     *
     * @return true if key exists, false otherwise.
     */
385
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
386
    inline bool exists(const database& db, const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
387
        return exists(db, object_data(key), object_size(key));
388 389 390 391 392 393
    }

    //////////////////////////
    // LENGTH methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
394 395 396 397 398 399 400 401 402
    /**
     * @brief Length of the value associated with the provided key.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key.
     *
     * @return size of the corresponding value.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
403 404
    hg_size_t length(const database& db,
            const void* key, hg_size_t ksize) const;
405

Matthieu Dorier's avatar
Matthieu Dorier committed
406 407 408 409 410 411 412 413 414 415 416
    /**
     * @brief Templated version of the length method, meant to
     * work with std::vector<X> and std::string. X must be a standard
     * layout type.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param key Key.
     *
     * @return size of the corresponding value.
     */
417
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
418
    inline hg_size_t length(const database& db,
419
            const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
420
        return length(db, object_data(key), object_size(key));
421 422 423 424 425 426
    }

    //////////////////////////
    // LENGTH_MULTI methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
427 428 429 430 431 432 433 434 435
    /**
     * @brief Equivalent to sdskv_length_multi.
     *
     * @param db Database instance.
     * @param num Number of keys.
     * @param keys Array of keys.
     * @param ksizes Array of key sizes.
     * @param vsizes Resulting value sizes.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
436
    bool length_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
437 438
            hg_size_t num, const void* const* keys,
            const hg_size_t* ksizes, hg_size_t* vsizes) const;
439

Matthieu Dorier's avatar
Matthieu Dorier committed
440 441 442 443 444 445 446 447 448
    /**
     * @brief Templated version of length, meant to work with
     * std::vector<X> and std::string. X must be a standard layout type.
     *
     * @tparam K Type of keys.
     * @param db Database instance.
     * @param keys Vector of keys.
     * @param vsizes Resulting vector of value sizes.
     */
449
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
450
    inline bool length_multi(const database& db,
451
            const std::vector<K>& keys,
Matthieu Dorier's avatar
Matthieu Dorier committed
452
            std::vector<hg_size_t>& vsizes) const {
453 454
        vsizes.resize(keys.size());
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
455
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
456
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
457 458
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
459
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
460
        return length_multi(db, keys.size(), kdata.data(), ksizes.data(), vsizes.data());
461 462
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
463 464 465 466 467 468 469 470 471 472 473
    /**
     * @brief Templated version of length returning a vector of sizes.
     * Meant to work with std::vector<X> and std::string.
     * X must be a standard layout type.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param keys Vector of keys.
     *
     * @return Vector of corresponding value sizes.
     */
474
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
475
    inline std::vector<hg_size_t> length_multi(const database& db, const std::vector<K>& keys) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
476
        std::vector<hg_size_t> vsizes(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
477
        length_multi(db, keys, vsizes);
478 479 480
        return vsizes;
    }

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512
    //////////////////////////
    // LENGTH_PACKED methods
    //////////////////////////

    /**
     * @brief Equivalent to sdskv_length_packed.
     *
     * @param db Database instance.
     * @param num Number of keys.
     * @param keys Packed keys.
     * @param ksizes Array of key sizes.
     * @param vsizes Resulting value sizes.
     */
    bool length_packed(const database& db,
            hg_size_t num, const void* keys,
            const hg_size_t* ksizes, hg_size_t* vsizes) const;

    /**
     * Version of length_packed that takes an std::string as packed buffer.
     *
     * @param db Database instance.
     * @param keys Packed keys.
     * @param vsizes Resulting vector of value sizes.
     */
    inline bool length_multi(const database& db,
            const std::string& keys,
            const std::vector<hg_size_t>& ksizes,
            std::vector<hg_size_t>& vsizes) const {
        vsizes.resize(ksizes.size());
        return length_packed(db, ksizes.size(), keys.data(), ksizes.data(), vsizes.data());
    }

513 514 515 516
    //////////////////////////
    // GET methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
517 518 519 520 521 522 523 524 525 526
    /**
     * @brief Equivalent of sdskv_get. Will throw an exception if the key doesn't exist,
     * or if the buffer allocated for the value is too small.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key.
     * @param value Pointer to a buffer allocated for the value.
     * @param vsize Size of the value buffer.
     */
527
    bool get(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
528 529
             const void* key, hg_size_t ksize,
             void* value, hg_size_t* vsize) const;
530

Matthieu Dorier's avatar
Matthieu Dorier committed
531 532 533 534 535 536 537 538 539 540
    /**
     * @brief Templated version of get, meant to be used with std::vector<X> and std::string.
     * X must be a standard layout type.
     *
     * @tparam K Key type.
     * @tparam V Value type.
     * @param db Database instance.
     * @param key Key.
     * @param value Value.
     */
541
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
542
    inline bool get(const database& db,
543
             const K& key, V& value) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
544 545 546
        hg_size_t s = value.size();
        if(s == 0) {
            s = length(db, key);
Matthieu Dorier's avatar
Matthieu Dorier committed
547
            object_resize(value, s);
Matthieu Dorier's avatar
Matthieu Dorier committed
548
        }
549 550 551 552 553 554 555 556 557 558
        try {
            get(db, object_data(key), object_size(key), object_data(value), &s);
        } catch(exception& ex) {
            if(ex.error() == SDSKV_ERR_SIZE) {
                object_resize(value, s);
                get(db, object_data(key), object_size(key), object_data(value), &s);
            } else {
                throw;
            }
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
559
        object_resize(value, s);
560 561 562
        return true;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
563 564 565 566 567 568 569 570 571 572 573 574
    /**
     * @brief Get method returning its value instead of using an argument.
     * Meant to work with K and V being std::string or std::vector<X, with
     * X a standard layout type.
     *
     * @tparam K Key type.
     * @tparam V Value type.
     * @param db Database instance.
     * @param key Key.
     *
     * @return The value associated with the provided key.
     */
575
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
576
    inline V get(const database& db,
577
          const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
578
        V value;
579 580 581 582 583 584 585 586
        get(db, key, value);
        return value;
    }

    //////////////////////////
    // GET_MULTI methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
587 588 589 590 591 592 593 594 595 596
    /**
     * @brief Equivalent to sdskv_get_multi.
     *
     * @param db Database instance.
     * @param count Number of key/val pairs.
     * @param keys Array of keys.
     * @param ksizes Array of key sizes.
     * @param values Array of value buffers.
     * @param vsizes Array of sizes of value buffers.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
597
    bool get_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
598 599
             hg_size_t count, const void* const* keys, const hg_size_t* ksizes,
             void** values, hg_size_t *vsizes) const;
600

Matthieu Dorier's avatar
Matthieu Dorier committed
601 602 603 604 605 606 607 608 609
    /**
     * @brief Get multiple key/val pairs using std::vector of addresses.
     *
     * @param db Database instance.
     * @param keys Vector of key addresses.
     * @param ksizes Vector of key sizes.
     * @param values Vector of value addresses.
     * @param vsizes Vector of value sizes.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
610
    inline bool get_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
611 612
             const std::vector<const void*>& keys, const std::vector<hg_size_t>& ksizes,
             std::vector<void*>& values, std::vector<hg_size_t>& vsizes) const {
613 614 615 616 617
        if(keys.size() != ksizes.size()
        || keys.size() != values.size()
        || keys.size() != vsizes.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
618
        return get_multi(db, keys.size(), keys.data(),  ksizes.data(), values.data(), vsizes.data());
619 620
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
621 622 623 624 625 626 627 628 629 630 631
    /**
     * @brief Get multiple key/val pairs using templated keys and values.
     * Meant to work with std::string and std::vector<X> where X is a standard
     * layout type.
     *
     * @tparam K Key type.
     * @tparam V Value type.
     * @param db Database instance.
     * @param keys Vector of keys.
     * @param values Vector of values.
     */
632
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
633
    inline bool get_multi(const database& db,
634 635 636 637 638
             const std::vector<K>& keys, std::vector<V>& values) const {
        if(keys.size() != values.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
639 640 641
        std::vector<void*> vdata; vdata.reserve(values.size());
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.size());
642
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
643 644
            ksizes.push_back(object_size(k));
            kdata.push_back(object_data(k));
645 646
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
647 648
            vsizes.push_back(object_size(v));
            vdata.push_back(object_data(v));
649
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
650
        get_multi(db, kdata, ksizes, vdata, vsizes);
Matthieu Dorier's avatar
Matthieu Dorier committed
651
        for(unsigned i=0; i < values.size(); i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
652
            object_resize(values[i], vsizes[i]);
Matthieu Dorier's avatar
Matthieu Dorier committed
653 654
        }
        return true;
655 656
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
657 658 659 660 661 662 663 664 665 666 667 668 669
    /**
     * @brief Get method using iterator to templated keys and values.
     * Meant to work with std::string and std::vector<X> with X a standard
     * layout type.
     *
     * @tparam IK Key iterator type.
     * @tparam IV Value iterator type.
     * @param db Database instance.
     * @param kbegin Beginning iterator for keys.
     * @param kend End iterator for keys.
     * @param vbegin Beginning iterator for values.
     * @param vend End iterator for values.
     */
670
    template<typename IK, typename IV>
Matthieu Dorier's avatar
Matthieu Dorier committed
671
    inline bool get_multi(const database& db,
672 673
             const IK& kbegin, const IK& kend,
             const IV& vbegin, const IV& vend) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
674
        hg_size_t count = std::distance(kbegin, kend);
675 676 677 678
        if(count != std::distance(vbegin, vend)) {
            throw std::length_error("Provided iterators should point to the same number of objects");
        }
        std::vector<const void*> kdata; kdata.reserve(count);
Matthieu Dorier's avatar
Matthieu Dorier committed
679
        std::vector<void*> vdata; vdata.reserve(count);
Matthieu Dorier's avatar
Matthieu Dorier committed
680 681
        std::vector<hg_size_t> ksizes; ksizes.reserve(count);
        std::vector<hg_size_t> vsizes; vsizes.reserve(count);
682
        for(auto it = kbegin; it != kend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
683
            ksizes.push_back(object_size(*it));
684
            kdata.push_back(object_data(*it));
685 686
        }
        for(auto it = vbegin; it != vend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
687
            vsizes.push_back(object_size(*it));
688
            vdata.push_back(object_data(*it));
689
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
690
        return get_multi(db, kdata, ksizes, vdata, vsizes);
691 692
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
693 694 695 696 697 698 699 700 701 702 703 704 705
    /**
     * @brief Get method that returns an a vector of values.
     * Meant to work with std::string and std::vector<X> where X
     * is a standard layout type.
     *
     * @tparam K Key type.
     * @tparam V Value type.
     * @param db Database instance.
     * @param keys Keys.
     *
     * @return the resulting std::vector of values.
     */
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
706
    inline std::vector<V> get_multi(
707 708
            const database& db,
            const std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
709 710
        hg_size_t num = keys.size();
        std::vector<hg_size_t> vsizes(num);
Matthieu Dorier's avatar
Matthieu Dorier committed
711
        length_multi(db, keys, vsizes);
Matthieu Dorier's avatar
Matthieu Dorier committed
712
        std::vector<V> values(num);
713
        for(unsigned i=0 ; i < num; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
714
            object_resize(values[i], vsizes[i]);
715
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
716
        get_multi(db, keys, values);
717 718 719
        return values;
    }

720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
    //////////////////////////
    // GET_PACKED methods
    //////////////////////////

    /**
     * @brief Equivalent to sdskv_get_packed.
     *
     * @param db Database instance.
     * @param count Number of key/val pairs.
     * @param keys Buffer of packed keys.
     * @param ksizes Array of key sizes.
     * @param valbufsize Size of the value buffer.
     * @param values Buffer of packed values.
     * @param vsizes Array of sizes of value buffers.
     */
    bool get_packed(const database& db,
             hg_size_t* count, const void* keys, const hg_size_t* ksizes,
             hg_size_t valbufsize, void* values, hg_size_t *vsizes) const;

    /**
     * @brief Get multiple key/val pairs using std::string packed buffers
     * and std::vector<hg_size_t> of sizes. The value buffer must be
     * pre-allocated. vsizes will be resized to the right number of retrieved
     * values.
     *
     * @param db Database instance.
     * @param keys Vector of key addresses.
     * @param ksizes Vector of key sizes.
     * @param values Vector of value addresses.
     * @param vsizes Vector of value sizes.
     */
    inline bool get_packed(const database& db,
             const std::string& packed_keys, const std::vector<hg_size_t>& ksizes,
             std::string& packed_values, std::vector<hg_size_t>& vsizes) const {
        hg_size_t count = ksizes.size();
        vsizes.resize(count);
        bool b = get_packed(db, &count, packed_keys.data(), ksizes.data(),
                packed_values.size(), const_cast<char*>(packed_values.data()), vsizes.data());
        vsizes.resize(count);
        return b;
    }


763 764 765 766
    //////////////////////////
    // ERASE methods
    //////////////////////////
    
Matthieu Dorier's avatar
Matthieu Dorier committed
767 768 769 770 771 772 773
    /**
     * @brief Equivalent to sdskv_erase.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key.
     */
774 775
    void erase(const database& db,
               const void* key,
Matthieu Dorier's avatar
Matthieu Dorier committed
776
               hg_size_t ksize) const;
777

Matthieu Dorier's avatar
Matthieu Dorier committed
778 779 780 781 782 783 784 785 786
    /**
     * @brief Templated erase method, meant to be used
     * with keys of type std::string or std::vector<X> where X is a
     * standard layout type.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param key Key.
     */
787
    template<typename K>
788
    inline void erase(const database& db,
789
               const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
790
        erase(db, object_data(key), object_size(key));
791 792 793 794 795 796
    }

    //////////////////////////
    // ERASE_MULTI methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
797 798 799 800 801 802 803 804
    /**
     * @brief Equivalent to sdskv_erase_multi.
     *
     * @param db Database instance.
     * @param num Number of key/value pairs to erase.
     * @param keys Array of keys.
     * @param ksizes Array of key sizes.
     */
805
    void erase_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
806 807
            hg_size_t num, const void* const* keys,
            const hg_size_t* ksizes) const;
808

Matthieu Dorier's avatar
Matthieu Dorier committed
809 810 811 812 813 814 815 816 817
    /**
     * @brief Erase a vector of keys. The key type K should be
     * std::string or std::vector<X> with X being a standard layout
     * type.
     *
     * @tparam K Type of 
     * @param db Database instance.
     * @param keys Vector of keys to erase.
     */
818
    template<typename K>
819
    inline void erase_multi(const database& db,
820 821
            const std::vector<K>& keys) const {
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
822
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
823
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
824 825
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
826
        }
827
        return erase_multi(db, keys.size(), kdata.data(), ksizes.data());
828 829 830 831 832 833
    }

    //////////////////////////
    // LIST_KEYS methods
    //////////////////////////
    
Matthieu Dorier's avatar
Matthieu Dorier committed
834 835 836 837 838 839 840 841 842 843 844 845
    /**
     * @brief Equivalent to sdskv_list_keys.
     *
     * @param db Database instance.
     * @param start_key Starting key (excluded from results).
     * @param start_ksize Starting key size.
     * @param prefix Prefix.
     * @param prefix_size Prefix size.
     * @param keys Resulting key buffers.
     * @param ksizes Resulting key buffer sizes.
     * @param max_keys Max number of keys.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
846
    void list_keys(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
847 848 849
            const void *start_key, hg_size_t start_ksize,
            const void *prefix, hg_size_t prefix_size,
            void** keys, hg_size_t* ksizes, hg_size_t* max_keys) const;
850

Matthieu Dorier's avatar
Matthieu Dorier committed
851 852 853
    inline void list_keys(const database& db,
            const void *start_key, hg_size_t start_ksize,
            void** keys, hg_size_t* ksizes, hg_size_t* max_keys) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
854
        list_keys(db, start_key, start_ksize, NULL, 0, keys, ksizes, max_keys);
855 856
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
857 858 859 860 861 862 863 864 865
    /**
     * @brief List keys starting from a given key (excluded).
     * K must be std::string or std::vector<X> with X a standard layout type.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param start_key Start key.
     * @param keys Resulting keys.
     */
866
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
867
    inline void list_keys(const database& db,
868 869
                const K& start_key,
                std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
870 871
        hg_size_t max_keys = keys.size();
        if(max_keys == 0) return;
872
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
873
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
874
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
875 876
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
877 878
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
879
            list_keys(db, object_data(start_key), object_size(start_key),
880 881
                kdata.data(), ksizes.data(), &max_keys);
        } catch(exception& e) {
Matthieu Dorier's avatar
Matthieu Dorier committed
882
            if(e.error() == SDSKV_ERR_SIZE && keys[0].size() == 0) {
883
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
884 885
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
886
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
887
                list_keys(db, object_data(start_key), object_size(start_key),
888 889 890 891 892 893
                        kdata.data(), ksizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
894
            object_resize(keys[i], ksizes[i]);
895 896 897 898
        }
        keys.resize(max_keys);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
899 900 901 902 903 904 905 906 907
    /**
     * @brief List keys with a prefix.
     *
     * @tparam K Key type.
     * @param db Database instance.
     * @param start_key Start key (excluded from results).
     * @param prefix Prefix.
     * @param keys Resulting keys.
     */
908
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
909
    inline void list_keys(const database& db,
910 911 912
                const K& start_key,
                const K& prefix,
                std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
913
        hg_size_t max_keys = keys.size();
914
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
915
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
916
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
917 918
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
919 920
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
921 922
            list_keys(db, object_data(start_key), object_size(start_key),
                object_data(prefix), object_size(prefix),
923 924
                kdata.data(), ksizes.data(), &max_keys);
        } catch(exception& e) {
Matthieu Dorier's avatar
Matthieu Dorier committed
925
            if(e.error() == SDSKV_ERR_SIZE && object_size(keys[0]) == 0) {
926
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
927 928
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
929
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
930 931
                list_keys(db, object_data(start_key), object_size(start_key),
                        object_data(prefix), object_size(prefix),
932 933 934 935 936 937
                        kdata.data(), ksizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
938
            object_resize(keys[i], ksizes[i]);
939 940 941 942 943 944 945 946
        }
        keys.resize(max_keys);
    }

    //////////////////////////
    // LIST_KEYVALS methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
947 948 949
    /**
     * @brief Same as list_keys but also returns the values.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
950
    void list_keyvals(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
951 952 953 954 955 956
            const void *start_key, hg_size_t start_ksize,
            const void *prefix, hg_size_t prefix_size,
            void** keys, hg_size_t* ksizes, 
            void** values, hg_size_t* vsizes,
            hg_size_t* max_items) const;

Matthieu Dorier's avatar
Matthieu Dorier committed
957 958 959
    /**
     * @brief Same as list_keys but also returns the values.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
960 961 962 963 964
    inline void list_keyvals(const database& db,
            const void *start_key, hg_size_t start_ksize,
            void** keys, hg_size_t* ksizes,
            void** values, hg_size_t* vsizes,
            hg_size_t* max_items) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
965
        list_keyvals(db, start_key, start_ksize,
966 967 968
                NULL, 0, keys, ksizes, values, vsizes, max_items);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
969 970 971
    /**
     * @brief Same as list_keys but also returns the values.
     */
972
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
973
    inline void list_keyvals(const database& db,
974 975 976 977
                const K& start_key,
                std::vector<K>& keys,
                std::vector<V>& values) const {

Matthieu Dorier's avatar
Matthieu Dorier committed
978
        hg_size_t max_keys = std::min(keys.size(), values.size());
979
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
980
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
981
        std::vector<void*> vdata; vdata.reserve(values.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
982
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.size());
983
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
984 985
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
986 987
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
988 989
            vdata.push_back(object_data(v));
            vsizes.push_back(object_size(v));
990 991
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
992
            list_keyvals(db, object_data(start_key), object_size(start_key),
993 994 995 996 997
                kdata.data(), ksizes.data(), 
                vdata.data(), vsizes.data(), &max_keys);
        } catch(exception& e) {
            if(e.error() == SDSKV_ERR_SIZE) {
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
998 999 1000 1001
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
                    object_resize(values[i], vsizes[i]);
                    vdata[i] = object_data(values[i]);
1002
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
1003
                list_keyvals(db, object_data(start_key), object_size(start_key),
1004 1005 1006 1007 1008 1009 1010
                    kdata.data(), ksizes.data(), 
                    vdata.data(), vsizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1011 1012
            object_resize(keys[i], ksizes[i]);
            object_resize(values[i], vsizes[i]);
1013 1014 1015 1016 1017
        }
        keys.resize(max_keys);
        values.resize(max_keys);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
1018 1019 1020
    /**
     * @brief Same as list_keys but also returns the values.
     */
1021
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
1022
    inline void list_keyvals(const database& db,
1023 1024 1025 1026 1027
                const K& start_key,
                const K& prefix,
                std::vector<K>& keys,
                std::vector<V>& values) const {

Matthieu Dorier's avatar
Matthieu Dorier committed
1028
        hg_size_t max_keys = std::min(keys.size(), values.size());
1029
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
1030
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
1031
        std::vector<void*> vdata; vdata.reserve(values.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
1032
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.size());
1033
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1034 1035
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
1036 1037
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1038 1039
            vdata.push_back(object_data(v));
            vsizes.push_back(object_size(v));
1040 1041
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
1042 1043
            list_keyvals(db, object_data(start_key), object_size(start_key),
                object_data(prefix), object_size(prefix),
1044 1045 1046 1047 1048
                kdata.data(), ksizes.data(), 
                vdata.data(), vsizes.data(), &max_keys);
        } catch(exception& e) {
            if(e.error() == SDSKV_ERR_SIZE) {
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1049 1050 1051 1052
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
                    object_resize(values[i], vsizes[i]);
                    vdata[i] = object_data(values[i]);
1053
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
1054 1055
                list_keyvals(db, object_data(start_key), object_size(start_key),
                        object_data(prefix), object_size(prefix),
1056 1057 1058 1059 1060 1061 1062
                        kdata.data(), ksizes.data(), 
                        vdata.data(), vsizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1063 1064
            object_resize(keys[i], ksizes[i]);
            object_resize(values[i], vsizes[i]);
1065 1066 1067 1068 1069 1070 1071 1072