sdskv-client.hpp 51.8 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 225 226 227 228 229 230
    /**
     * @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.
     */
231
    void put(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
232 233
             hg_size_t count, const void* const* keys, const hg_size_t* ksizes,
             const void* const* values, const hg_size_t *vsizes) const;
234 235 236 237 238

    //////////////////////////
    // PUT_MULTI methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
239 240 241 242 243 244 245 246 247
    /**
     * @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
248 249 250
    inline void put(const database& db,
             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 {
251 252 253 254 255 256 257 258
        if(keys.size() != ksizes.size()
        || keys.size() != values.size()
        || keys.size() != vsizes.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
        put(db, keys.size(), keys.data(),  ksizes.data(), values.data(), vsizes.data());
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
259 260 261 262 263 264 265 266 267 268
    /**
     * @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.
     */
269
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
270
    inline void put(const database& db,
271 272 273 274 275
             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
276 277 278
        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());
279
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
280 281
            ksizes.push_back(object_size(k));
            kdata.push_back(object_data(k));
282 283
        }
        for(const auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
284 285
            vsizes.push_back(object_size(v));
            vdata.push_back(object_data(v));
286 287 288 289
        }
        put(db, kdata, ksizes, vdata, vsizes);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
290 291 292 293 294 295 296 297 298 299 300 301 302
    /**
     * @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.
     */
303
    template<typename IK, typename IV>
Matthieu Dorier's avatar
Matthieu Dorier committed
304
    inline void put(const database& db,
305 306
             const IK& kbegin, const IK& kend,
             const IV& vbegin, const IV& vend) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
307
        hg_size_t count = std::distance(kbegin, kend);
308 309 310 311 312
        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
313 314
        std::vector<hg_size_t> ksizes; ksizes.reserve(count);
        std::vector<hg_size_t> vsizes; vsizes.reserve(count);
315
        for(auto it = kbegin; it != kend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
316
            ksizes.push_back(object_size(*it));
317
            kdata.push_back(object_data(*it));
318 319
        }
        for(auto it = vbegin; it != vend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
320
            vsizes.push_back(object_size(*it));
321
            vdata.push_back(object_data(*it));
322 323 324 325 326 327 328 329
        }
        put(db, kdata, ksizes, vdata, vsizes);
    }

    //////////////////////////
    // EXISTS methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
330 331 332 333 334 335 336 337 338
    /**
     * @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
339
    bool exists(const database& db, const void* key, hg_size_t ksize) const;
340

Matthieu Dorier's avatar
Matthieu Dorier committed
341 342 343 344 345 346 347 348 349 350
    /**
     * @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.
     */
351
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
352
    inline bool exists(const database& db, const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
353
        return exists(db, object_data(key), object_size(key));
354 355 356 357 358 359
    }

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

Matthieu Dorier's avatar
Matthieu Dorier committed
360 361 362 363 364 365 366 367 368
    /**
     * @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
369 370
    hg_size_t length(const database& db,
            const void* key, hg_size_t ksize) const;
371

Matthieu Dorier's avatar
Matthieu Dorier committed
372 373 374 375 376 377 378 379 380 381 382
    /**
     * @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.
     */
383
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
384
    inline hg_size_t length(const database& db,
385
            const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
386
        return length(db, object_data(key), object_size(key));
387 388 389 390 391 392
    }

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

Matthieu Dorier's avatar
Matthieu Dorier committed
393 394 395 396 397 398 399 400 401
    /**
     * @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.
     */
402
    bool length(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
403 404
            hg_size_t num, const void* const* keys,
            const hg_size_t* ksizes, hg_size_t* vsizes) const;
405

Matthieu Dorier's avatar
Matthieu Dorier committed
406 407 408 409 410 411 412 413 414
    /**
     * @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.
     */
415
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
416
    inline bool length(const database& db,
417
            const std::vector<K>& keys,
Matthieu Dorier's avatar
Matthieu Dorier committed
418
            std::vector<hg_size_t>& vsizes) const {
419 420
        vsizes.resize(keys.size());
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
421
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
422
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
423 424
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
425 426 427 428
        }
        return length(db, keys.size(), kdata.data(), ksizes.data(), vsizes.data());
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
429 430 431 432 433 434 435 436 437 438 439
    /**
     * @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.
     */
440
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
441 442 443
    inline std::vector<hg_size_t> length(const database& db, const std::vector<K>& keys) const {
        std::vector<hg_size_t> vsizes(keys.size());
        length(db, keys, vsizes);
444 445 446 447 448 449 450
        return vsizes;
    }

    //////////////////////////
    // GET methods
    //////////////////////////

Matthieu Dorier's avatar
Matthieu Dorier committed
451 452 453 454 455 456 457 458 459 460
    /**
     * @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.
     */
461
    bool get(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
462 463
             const void* key, hg_size_t ksize,
             void* value, hg_size_t* vsize) const;
464

Matthieu Dorier's avatar
Matthieu Dorier committed
465 466 467 468 469 470 471 472 473 474
    /**
     * @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.
     */
475
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
476
    inline bool get(const database& db,
477
             const K& key, V& value) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
478 479 480
        hg_size_t s = value.size();
        if(s == 0) {
            s = length(db, key);
Matthieu Dorier's avatar
Matthieu Dorier committed
481
            object_resize(value, s);
Matthieu Dorier's avatar
Matthieu Dorier committed
482
        }
483 484 485 486 487 488 489 490 491 492
        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
493
        object_resize(value, s);
494 495 496
        return true;
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
497 498 499 500 501 502 503 504 505 506 507 508
    /**
     * @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.
     */
509
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
510
    inline V get(const database& db,
511
          const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
512
        V value;
513 514 515 516 517 518 519 520
        get(db, key, value);
        return value;
    }

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

Matthieu Dorier's avatar
Matthieu Dorier committed
521 522 523 524 525 526 527 528 529 530
    /**
     * @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.
     */
531
    bool get(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
532 533
             hg_size_t count, const void* const* keys, const hg_size_t* ksizes,
             void** values, hg_size_t *vsizes) const;
534

Matthieu Dorier's avatar
Matthieu Dorier committed
535 536 537 538 539 540 541 542 543
    /**
     * @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
544 545 546
    inline bool get(const database& db,
             const std::vector<const void*>& keys, const std::vector<hg_size_t>& ksizes,
             std::vector<void*>& values, std::vector<hg_size_t>& vsizes) const {
547 548 549 550 551 552 553 554
        if(keys.size() != ksizes.size()
        || keys.size() != values.size()
        || keys.size() != vsizes.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
        return get(db, keys.size(), keys.data(),  ksizes.data(), values.data(), vsizes.data());
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
555 556 557 558 559 560 561 562 563 564 565
    /**
     * @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.
     */
566
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
567
    inline bool get(const database& db,
568 569 570 571 572
             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
573 574 575
        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());
576
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
577 578
            ksizes.push_back(object_size(k));
            kdata.push_back(object_data(k));
579 580
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
581 582
            vsizes.push_back(object_size(v));
            vdata.push_back(object_data(v));
583
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
584 585
        get(db, kdata, ksizes, vdata, vsizes);
        for(unsigned i=0; i < values.size(); i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
586
            object_resize(values[i], vsizes[i]);
Matthieu Dorier's avatar
Matthieu Dorier committed
587 588
        }
        return true;
589 590
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
591 592 593 594 595 596 597 598 599 600 601 602 603
    /**
     * @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.
     */
604
    template<typename IK, typename IV>
Matthieu Dorier's avatar
Matthieu Dorier committed
605
    inline bool get(const database& db,
606 607
             const IK& kbegin, const IK& kend,
             const IV& vbegin, const IV& vend) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
608
        hg_size_t count = std::distance(kbegin, kend);
609 610 611 612
        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
613
        std::vector<void*> vdata; vdata.reserve(count);
Matthieu Dorier's avatar
Matthieu Dorier committed
614 615
        std::vector<hg_size_t> ksizes; ksizes.reserve(count);
        std::vector<hg_size_t> vsizes; vsizes.reserve(count);
616
        for(auto it = kbegin; it != kend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
617
            ksizes.push_back(object_size(*it));
618
            kdata.push_back(object_data(*it));
619 620
        }
        for(auto it = vbegin; it != vend; it++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
621
            vsizes.push_back(object_size(*it));
622
            vdata.push_back(object_data(*it));
623 624 625 626
        }
        return get(db, kdata, ksizes, vdata, vsizes);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
627 628 629 630 631 632 633 634 635 636 637 638 639 640
    /**
     * @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>
    inline std::vector<V> get(
641 642
            const database& db,
            const std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
643 644
        hg_size_t num = keys.size();
        std::vector<hg_size_t> vsizes(num);
645
        length(db, keys, vsizes);
Matthieu Dorier's avatar
Matthieu Dorier committed
646
        std::vector<V> values(num);
647
        for(unsigned i=0 ; i < num; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
648
            object_resize(values[i], vsizes[i]);
649
        }
Matthieu Dorier's avatar
Matthieu Dorier committed
650
        get(db, keys, values);
651 652 653 654 655 656 657
        return values;
    }

    //////////////////////////
    // ERASE methods
    //////////////////////////
    
Matthieu Dorier's avatar
Matthieu Dorier committed
658 659 660 661 662 663 664
    /**
     * @brief Equivalent to sdskv_erase.
     *
     * @param db Database instance.
     * @param key Key.
     * @param ksize Size of the key.
     */
665 666
    void erase(const database& db,
               const void* key,
Matthieu Dorier's avatar
Matthieu Dorier committed
667
               hg_size_t ksize) const;
668

Matthieu Dorier's avatar
Matthieu Dorier committed
669 670 671 672 673 674 675 676 677
    /**
     * @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.
     */
678
    template<typename K>
679
    inline void erase(const database& db,
680
               const K& key) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
681
        erase(db, object_data(key), object_size(key));
682 683 684 685 686 687
    }

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

Matthieu Dorier's avatar
Matthieu Dorier committed
688 689 690 691 692 693 694 695
    /**
     * @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.
     */
696
    void erase_multi(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
697 698
            hg_size_t num, const void* const* keys,
            const hg_size_t* ksizes) const;
699

Matthieu Dorier's avatar
Matthieu Dorier committed
700 701 702 703 704 705 706 707 708
    /**
     * @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.
     */
709
    template<typename K>
710
    inline void erase_multi(const database& db,
711 712
            const std::vector<K>& keys) const {
        std::vector<const void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
713
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
714
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
715 716
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
717
        }
718
        return erase_multi(db, keys.size(), kdata.data(), ksizes.data());
719 720 721 722 723 724
    }

    //////////////////////////
    // LIST_KEYS methods
    //////////////////////////
    
Matthieu Dorier's avatar
Matthieu Dorier committed
725 726 727 728 729 730 731 732 733 734 735 736
    /**
     * @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
737
    void list_keys(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
738 739 740
            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;
741

Matthieu Dorier's avatar
Matthieu Dorier committed
742 743 744
    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
745
        list_keys(db, start_key, start_ksize, NULL, 0, keys, ksizes, max_keys);
746 747
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
748 749 750 751 752 753 754 755 756
    /**
     * @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.
     */
757
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
758
    inline void list_keys(const database& db,
759 760
                const K& start_key,
                std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
761 762
        hg_size_t max_keys = keys.size();
        if(max_keys == 0) return;
763
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
764
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
765
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
766 767
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
768 769
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
770
            list_keys(db, object_data(start_key), object_size(start_key),
771 772
                kdata.data(), ksizes.data(), &max_keys);
        } catch(exception& e) {
Matthieu Dorier's avatar
Matthieu Dorier committed
773
            if(e.error() == SDSKV_ERR_SIZE && keys[0].size() == 0) {
774
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
775 776
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
777
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
778
                list_keys(db, object_data(start_key), object_size(start_key),
779 780 781 782 783 784
                        kdata.data(), ksizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
785
            object_resize(keys[i], ksizes[i]);
786 787 788 789
        }
        keys.resize(max_keys);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
790 791 792 793 794 795 796 797 798
    /**
     * @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.
     */
799
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
800
    inline void list_keys(const database& db,
801 802 803
                const K& start_key,
                const K& prefix,
                std::vector<K>& keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
804
        hg_size_t max_keys = keys.size();
805
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
806
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
807
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
808 809
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
810 811
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
812 813
            list_keys(db, object_data(start_key), object_size(start_key),
                object_data(prefix), object_size(prefix),
814 815
                kdata.data(), ksizes.data(), &max_keys);
        } catch(exception& e) {
Matthieu Dorier's avatar
Matthieu Dorier committed
816
            if(e.error() == SDSKV_ERR_SIZE && object_size(keys[0]) == 0) {
817
                for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
818 819
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
820
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
821 822
                list_keys(db, object_data(start_key), object_size(start_key),
                        object_data(prefix), object_size(prefix),
823 824 825 826 827 828
                        kdata.data(), ksizes.data(), &max_keys);
            } else {
                throw;
            }
        }
        for(unsigned i=0; i < max_keys; i++) {
Matthieu Dorier's avatar
Matthieu Dorier committed
829
            object_resize(keys[i], ksizes[i]);
830 831 832 833 834 835 836 837
        }
        keys.resize(max_keys);
    }

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

Matthieu Dorier's avatar
Matthieu Dorier committed
838 839 840
    /**
     * @brief Same as list_keys but also returns the values.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
841
    void list_keyvals(const database& db,
Matthieu Dorier's avatar
Matthieu Dorier committed
842 843 844 845 846 847
            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
848 849 850
    /**
     * @brief Same as list_keys but also returns the values.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
851 852 853 854 855
    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
856
        list_keyvals(db, start_key, start_ksize,
857 858 859
                NULL, 0, keys, ksizes, values, vsizes, max_items);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
860 861 862
    /**
     * @brief Same as list_keys but also returns the values.
     */
863
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
864
    inline void list_keyvals(const database& db,
865 866 867 868
                const K& start_key,
                std::vector<K>& keys,
                std::vector<V>& values) const {

Matthieu Dorier's avatar
Matthieu Dorier committed
869
        hg_size_t max_keys = std::min(keys.size(), values.size());
870
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
871
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
872
        std::vector<void*> vdata; vdata.reserve(values.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
873
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.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
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
879 880
            vdata.push_back(object_data(v));
            vsizes.push_back(object_size(v));
881 882
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
883
            list_keyvals(db, object_data(start_key), object_size(start_key),
884 885 886 887 888
                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
889 890 891 892
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
                    object_resize(values[i], vsizes[i]);
                    vdata[i] = object_data(values[i]);
893
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
894
                list_keyvals(db, object_data(start_key), object_size(start_key),
895 896 897 898 899 900 901
                    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
902 903
            object_resize(keys[i], ksizes[i]);
            object_resize(values[i], vsizes[i]);
904 905 906 907 908
        }
        keys.resize(max_keys);
        values.resize(max_keys);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
909 910 911
    /**
     * @brief Same as list_keys but also returns the values.
     */
912
    template<typename K, typename V>
Matthieu Dorier's avatar
Matthieu Dorier committed
913
    inline void list_keyvals(const database& db,
914 915 916 917 918
                const K& start_key,
                const K& prefix,
                std::vector<K>& keys,
                std::vector<V>& values) const {

Matthieu Dorier's avatar
Matthieu Dorier committed
919
        hg_size_t max_keys = std::min(keys.size(), values.size());
920
        std::vector<void*> kdata; kdata.reserve(keys.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
921
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
922
        std::vector<void*> vdata; vdata.reserve(values.size());
Matthieu Dorier's avatar
Matthieu Dorier committed
923
        std::vector<hg_size_t> vsizes; vsizes.reserve(values.size());
924
        for(auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
925 926
            kdata.push_back(object_data(k));
            ksizes.push_back(object_size(k));
927 928
        }
        for(auto& v : values) {
Matthieu Dorier's avatar
Matthieu Dorier committed
929 930
            vdata.push_back(object_data(v));
            vsizes.push_back(object_size(v));
931 932
        }
        try {
Matthieu Dorier's avatar
Matthieu Dorier committed
933 934
            list_keyvals(db, object_data(start_key), object_size(start_key),
                object_data(prefix), object_size(prefix),
935 936 937 938 939
                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
940 941 942 943
                    object_resize(keys[i], ksizes[i]);
                    kdata[i] = object_data(keys[i]);
                    object_resize(values[i], vsizes[i]);
                    vdata[i] = object_data(values[i]);
944
                }
Matthieu Dorier's avatar
Matthieu Dorier committed
945 946
                list_keyvals(db, object_data(start_key), object_size(start_key),
                        object_data(prefix), object_size(prefix),
947 948 949 950 951 952 953
                        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
954 955
            object_resize(keys[i], ksizes[i]);
            object_resize(values[i], vsizes[i]);
956 957 958 959 960 961 962 963 964
        }
        keys.resize(max_keys);
        values.resize(max_keys);
    }

    //////////////////////////
    // MIGRATE_KEYS methods
    //////////////////////////
    
Matthieu Dorier's avatar
Matthieu Dorier committed
965 966 967 968 969 970 971 972 973 974
    /**
     * @brief Migrates a given set of keys from a source to a destination database.
     *
     * @param source_db Source database.
     * @param dest_db Destination database.
     * @param num_items Number of items
     * @param keys Array of keys.
     * @param key_sizes Array of key sizes.
     * @param flag SDSKV_KEEP_ORIGINAL or SDSKV_REMOVE_ORIGINAL.
     */
975
    void migrate(const database& source_db, const database& dest_db,
Matthieu Dorier's avatar
Matthieu Dorier committed
976 977
            hg_size_t num_items, const void* const* keys, const hg_size_t* key_sizes,
            int flag = SDSKV_KEEP_ORIGINAL) const;
978

Matthieu Dorier's avatar
Matthieu Dorier committed
979 980 981 982 983 984 985 986 987
    /**
     * @brief Migrates a given set of keys from a source to a destination database.
     *
     * @param source_db Source database.
     * @param dest_db Destination database.
     * @param keys Array of keys.
     * @param ksizes Array of key sizes.
     * @param flag SDSKV_KEEP_ORIGINAL or SDSKV_REMOVE_ORIGINAL.
     */
Matthieu Dorier's avatar
Matthieu Dorier committed
988
    inline void migrate(const database& source_db, const database& dest_db,
989
            const std::vector<const void*> keys, 
Matthieu Dorier's avatar
Matthieu Dorier committed
990
            const std::vector<hg_size_t> ksizes,
991 992 993 994 995 996 997
            int flag = SDSKV_KEEP_ORIGINAL) const {
        if(keys.size() != ksizes.size()) {
            throw std::length_error("Provided vectors should have the same size");
        }
        migrate(source_db, dest_db, keys.size(), keys.data(), ksizes.data(), flag);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
998 999 1000 1001 1002 1003 1004 1005 1006
    /**
     * @brief Migrate a set of keys from a source to a destination database.
     *
     * @tparam K Key type.
     * @param source_db Source database.
     * @param dest_db Destination database.
     * @param keys Vector of keys.
     * @param flag SDSKV_KEEP_ORIGINAL or SDSKV_REMOVE_ORIGINAL.
     */
1007
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
1008
    inline void migrate(const database& source_db, const database& dest_db,
1009
            const std::vector<K> keys, int flag = SDSKV_KEEP_ORIGINAL) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
1010
        std::vector<hg_size_t> ksizes; ksizes.reserve(keys.size());
1011 1012
        std::vector<const void*> kdata; kdata.reserve(keys.size());
        for(const auto& k : keys) {
Matthieu Dorier's avatar
Matthieu Dorier committed
1013 1014
            ksizes.push_back(object_size(k));
            kdata.push_back(object_data(k));
1015 1016 1017 1018 1019
        }
        migrate(source_db, dest_db,
                kdata, ksizes, flag);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
1020 1021 1022 1023 1024 1025 1026 1027 1028
    /**
     * @brief Migrate a range of keys.
     *
     * @param source_db Source database.
     * @param dest_db Destination database.
     * @param key_range[2] Key range ] lb; ub [
     * @param key_sizes[2] Key sizes
     * @param flag SDSKV_KEEP_ORIGINAL or SDSKV_REMOVE_ORIGINAL.
     */
1029
    void migrate(const database& source_db, const database& dest_db,
Matthieu Dorier's avatar
Matthieu Dorier committed
1030 1031
            const void* key_range[2], const hg_size_t key_sizes[2],
            int flag = SDSKV_KEEP_ORIGINAL) const;
1032

Matthieu Dorier's avatar
Matthieu Dorier committed
1033 1034 1035 1036 1037 1038 1039 1040 1041
    /**
     * @brief Migrate a range of keys.
     *
     * @tparam K Key type.
     * @param source_db Source database.
     * @param dest_db Destination database.
     * @param key_range Key range ] lb; ub [.
     * @param flag SDSKV_KEEP_ORIGINAL or SDSKV_REMOVE_ORIGINAL.
     */
1042
    template<typename K>
Matthieu Dorier's avatar
Matthieu Dorier committed
1043
    inline void migrate(const database& source_db, const database& dest_db,
1044 1045
                 const std::pair<K,K>& key_range,
                 int flag = SDSKV_KEEP_ORIGINAL) const {
Matthieu Dorier's avatar
Matthieu Dorier committed
1046 1047
        const void* key_range_arr[2] = { object_data(key_range.first), object_data(key_range.second) };
        const hg_size_t key_sizes_arr[2] = { object_size(key_range.first), object_size(key_range.second) };
1048 1049 1050
        migrate(source_db, dest_db, key_range_arr, key_sizes_arr, flag);
    }

Matthieu Dorier's avatar
Matthieu Dorier committed
1051 1052 1053 1054 1055 1056 1057 1058 1059