Skip to content

Commit

Permalink
Introduce util/indirect.hh
Browse files Browse the repository at this point in the history
Contains functors for comparing and hashing pointers by pointed-to
values.

Message-Id: <[email protected]>
  • Loading branch information
tgrabiec authored and avikivity committed Mar 2, 2016
1 parent 1e4adf8 commit b3fc7c5
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 16 deletions.
19 changes: 3 additions & 16 deletions core/shared_ptr.hh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <functional>
#include <iostream>
#include "util/is_smart_ptr.hh"
#include "util/indirect.hh"

// This header defines two shared pointer facilities, lw_shared_ptr<> and
// shared_ptr<>, both modeled after std::shared_ptr<>.
Expand Down Expand Up @@ -684,24 +685,10 @@ std::ostream& operator<<(std::ostream& out, const shared_ptr<T>& p) {
}

template<typename T>
struct shared_ptr_equal_by_value {
bool operator()(const shared_ptr<T>& i1, const shared_ptr<T>& i2) const {
if (bool(i1) ^ bool(i2)) {
return false;
}
return !i1 || *i1 == *i2;
}
};
using shared_ptr_equal_by_value = indirect_equal_to<shared_ptr<T>>;

template<typename T>
struct shared_ptr_value_hash {
size_t operator()(const shared_ptr<T>& p) const {
if (p) {
return std::hash<T>()(*p);
}
return 0;
}
};
using shared_ptr_value_hash = indirect_hash<shared_ptr<T>>;

namespace std {

Expand Down
41 changes: 41 additions & 0 deletions tests/shared_ptr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
#define BOOST_TEST_MODULE core

#include <boost/test/included/unit_test.hpp>
#include <set>
#include <unordered_map>
#include "core/sstring.hh"
#include "core/shared_ptr.hh"

struct expected_exception : public std::exception {};
Expand Down Expand Up @@ -115,3 +118,41 @@ BOOST_AUTO_TEST_CASE(test_exception_thrown_from_constructor_is_propagated) {
BOOST_TEST_MESSAGE("Expected exception caught");
}
}

BOOST_AUTO_TEST_CASE(test_indirect_functors) {
{
std::multiset<shared_ptr<sstring>, indirect_less<shared_ptr<sstring>>> a_set;

a_set.insert(make_shared<sstring>("k3"));
a_set.insert(make_shared<sstring>("k1"));
a_set.insert(make_shared<sstring>("k2"));
a_set.insert(make_shared<sstring>("k4"));
a_set.insert(make_shared<sstring>("k0"));


auto i = a_set.begin();
BOOST_REQUIRE_EQUAL(sstring("k0"), *(*i++));
BOOST_REQUIRE_EQUAL(sstring("k1"), *(*i++));
BOOST_REQUIRE_EQUAL(sstring("k2"), *(*i++));
BOOST_REQUIRE_EQUAL(sstring("k3"), *(*i++));
BOOST_REQUIRE_EQUAL(sstring("k4"), *(*i++));
}

{
std::unordered_map<shared_ptr<sstring>, bool,
indirect_hash<shared_ptr<sstring>>, indirect_equal_to<shared_ptr<sstring>>> a_map;

a_map.emplace(make_shared<sstring>("k3"), true);
a_map.emplace(make_shared<sstring>("k1"), true);
a_map.emplace(make_shared<sstring>("k2"), true);
a_map.emplace(make_shared<sstring>("k4"), true);
a_map.emplace(make_shared<sstring>("k0"), true);

BOOST_REQUIRE(a_map.count(make_shared<sstring>("k0")));
BOOST_REQUIRE(a_map.count(make_shared<sstring>("k1")));
BOOST_REQUIRE(a_map.count(make_shared<sstring>("k2")));
BOOST_REQUIRE(a_map.count(make_shared<sstring>("k3")));
BOOST_REQUIRE(a_map.count(make_shared<sstring>("k4")));
BOOST_REQUIRE(!a_map.count(make_shared<sstring>("k5")));
}
}
70 changes: 70 additions & 0 deletions util/indirect.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* Copyright (C) 2016 ScyllaDB
*/

#pragma once

#include <memory>

// This header defines functors for comparing and hashing pointers by pointed-to values instead of pointer addresses.
//
// Examples:
//
// std::multiset<shared_ptr<sstring>, indirect_less<shared_ptr<sstring>>> _multiset;
//
// std::unordered_map<shared_ptr<sstring>, bool,
// indirect_hash<shared_ptr<sstring>>, indirect_equal_to<shared_ptr<sstring>>> _unordered_map;
//

template<typename Pointer, typename Equal = std::equal_to<typename std::pointer_traits<Pointer>::element_type>>
struct indirect_equal_to {
Equal _eq;
indirect_equal_to(Equal eq = Equal()) : _eq(std::move(eq)) {}
bool operator()(const Pointer& i1, const Pointer& i2) const {
if (bool(i1) ^ bool(i2)) {
return false;
}
return !i1 || _eq(*i1, *i2);
}
};

template<typename Pointer, typename Less = std::less<typename std::pointer_traits<Pointer>::element_type>>
struct indirect_less {
Less _cmp;
indirect_less(Less cmp = Less()) : _cmp(std::move(cmp)) {}
bool operator()(const Pointer& i1, const Pointer& i2) const {
if (i1 && i2) {
return _cmp(*i1, *i2);
}
return !i1 && i2;
}
};

template<typename Pointer, typename Hash = std::hash<typename std::pointer_traits<Pointer>::element_type>>
struct indirect_hash {
Hash _h;
indirect_hash(Hash h = Hash()) : _h(std::move(h)) {}
size_t operator()(const Pointer& p) const {
if (p) {
return _h(*p);
}
return 0;
}
};

0 comments on commit b3fc7c5

Please sign in to comment.