Commit fd5eeb5f authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Unsafe pre-sorted construction for sorted-vector containers

Summary:
[Folly] Unsafe pre-sorted construction for sorted-vector containers.

If the backing container type can be constructed directly in sorted order or can be determined in advance to be in sorted order, then a special constructor can help code take advantage of this condition by avoiding an extra invocation of `std::sort`.

Reviewed By: spalamarchuk

Differential Revision: D6708379

fbshipit-source-id: 25d886b0814dc9230c6046ed1e7f199fac47754e
parent ab21322d
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2016-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -262,6 +262,28 @@ inline in_place_index_tag<I> in_place_index(in_place_index_tag<I> = {}) {
struct initlist_construct_t {};
constexpr initlist_construct_t initlist_construct{};
/**
* A generic tag type to indicate that some constructor or method is in some way
* unsafe and should be used only with extreme care and with full test coverage,
* if ever.
*
* Example:
*
* void takes_numbers(std::vector<int> alist) {
* std::sort(alist.begin(), alist.end());
* takes_numbers_assume_sorted(folly::unsafe, alist);
* }
*
* void takes_numbers_assume_sorted(folly::unsafe_t, std::vector<int> alist) {
* assert(std::is_sorted(alist.begin(), alist.end())); // debug mode only
* for (i : alist) {
* // some behavior which is defined and safe only when alist is sorted ...
* }
* }
*/
struct unsafe_t {};
constexpr unsafe_t unsafe{};
/**
* A simple function object that passes its argument through unchanged.
*
......
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2011-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......@@ -60,6 +60,7 @@
#pragma once
#include <algorithm>
#include <cassert>
#include <initializer_list>
#include <iterator>
#include <stdexcept>
......@@ -70,6 +71,7 @@
#include <boost/operators.hpp>
#include <folly/Traits.h>
#include <folly/Utility.h>
#include <folly/portability/BitsFunctexcept.h>
namespace folly {
......@@ -193,6 +195,13 @@ void bulk_insert(
cont.end());
}
}
template <typename Container, typename Compare>
Container&& as_sorted(Container&& container, Compare const& comp) {
using namespace std;
std::sort(begin(container), end(container), comp);
return static_cast<Container&&>(container);
}
} // namespace detail
//////////////////////////////////////////////////////////////////////
......@@ -285,10 +294,28 @@ class sorted_vector_set
// Note that `sorted_vector_set(const Container& container)` is not provided,
// since the purpose of this constructor is to avoid an unnecessary copy.
explicit sorted_vector_set(
Container&& container,
const Compare& comp = Compare())
: sorted_vector_set(
unsafe,
detail::as_sorted(std::move(container), comp),
comp) {}
// Construct a sorted_vector_set by stealing the storage of a prefilled
// container. The container must be sorted, as unsafe_t hints. This supports
// bulk construction of sorted_vector_set with zero allocations, not counting
// those performed by the caller. (The iterator range constructor performs at
// least one allocation).
//
// Note that `sorted_vector_set(unsafe_t, const Container& container)` is not
// provided, since the purpose of this constructor is to avoid an unnecessary
// copy.
sorted_vector_set(
unsafe_t,
Container&& container,
const Compare& comp = Compare())
: m_(comp, container.get_allocator()) {
std::sort(container.begin(), container.end(), value_comp());
assert(std::is_sorted(container.begin(), container.end(), value_comp()));
m_.cont_.swap(container);
}
......@@ -596,10 +623,28 @@ class sorted_vector_map
// Note that `sorted_vector_map(const Container& container)` is not provided,
// since the purpose of this constructor is to avoid an unnecessary copy.
explicit sorted_vector_map(
Container&& container,
const Compare& comp = Compare())
: sorted_vector_map(
unsafe,
detail::as_sorted(std::move(container), value_compare(comp)),
comp) {}
// Construct a sorted_vector_map by stealing the storage of a prefilled
// container. The container must be sorted, as unsafe_t hints. This supports
// bulk construction of sorted_vector_map with zero allocations, not counting
// those performed by the caller. (The iterator range constructor performs at
// least one allocation).
//
// Note that `sorted_vector_map(unsafe_t, const Container& container)` is not
// provided, since the purpose of this constructor is to avoid an unnecessary
// copy.
sorted_vector_map(
unsafe_t,
Container&& container,
const Compare& comp = Compare())
: m_(value_compare(comp), container.get_allocator()) {
std::sort(container.begin(), container.end(), value_comp());
assert(std::is_sorted(container.begin(), container.end(), value_comp()));
m_.cont_.swap(container);
}
......
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2016-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2011-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment