Outline
Purpose
Provide an STL-compliant map class.
Classes
Canonical header: bsl_map.h
- See also
- bslstl_multimap, bslstl_set
Description
This component defines a single class template bsl::map
, implementing the standard container holding an ordered sequence of key-value pairs (having unique keys), and presenting a mapping from the keys (of a template parameter type, KEY
) to their associated values (of another template parameter type, VALUE
).
An instantiation of map
is an allocator-aware, value-semantic type whose salient attributes are its size (number of key-value pairs) and the ordered sequence of key-value pairs the map contains. If map
is instantiated with either a key type or mapped-value type that is not itself value-semantic, then it will not retain all of its value-semantic qualities. In particular, if either the key or value type cannot be tested for equality, then a map
containing that type cannot be tested for equality. It is even possible to instantiate map
with a key or mapped-value type that does not have a copy constructor, in which case the map
will not be copyable.
A map meets the requirements of an associative container with bidirectional iterators in the C++ standard [associative.reqmts]. The map
implemented here adheres to the C++11 standard when compiled with a C++11 compiler, and makes the best approximation when compiled with a C++03 compiler. In particular, for C++03 we emulate move semantics, but limit forwarding (in emplace
) to const
lvalues, and make no effort to emulate noexcept
or initializer-lists.
Requirements on KEY and VALUE
A map
is a fully Value-Semantic Type (see bsldoc_glossary ) only if the supplied KEY
and VALUE
template parameters are themselves fully value-semantic. It is possible to instantiate a map
with KEY
and VALUE
parameter arguments that do not provide a full set of value-semantic operations, but then some methods of the container may not be instantiable. The following terminology, adopted from the C++11 standard, is used in the function documentation of map
to describe a function's requirements for the KEY
and VALUE
template parameters. These terms are also defined in sections [utility.arg.requirements] and [container.requirements.general] of the C++11 standard. Note that, in the context of a map
instantiation, the requirements apply specifically to the map's entry type, value_type
, which is an alias for bsl::pair<const KEY, VALUE>
.
Glossary
Legend
------
'X' - denotes an allocator-aware container type (e.g., 'map')
'T' - 'value_type' associated with 'X'
'A' - type of the allocator used by 'X'
'm' - lvalue of type 'A' (allocator)
'p', - address ('T *') of uninitialized storage for a 'T' within an 'X'
'rv' - rvalue of type (non-'const') 'T'
'v' - rvalue or lvalue of type (possibly 'const') 'T'
'args' - 0 or more arguments
The following terms are used to more precisely specify the requirements on template parameter types in function-level documentation.
default-insertable: T
has a default constructor. More precisely, T
is default-insertable
into X
means that the following expression is well-formed: allocator_traits<A>::construct(m, p)
move-insertable: T
provides a constructor that takes an rvalue of type (non-const
) T
. More precisely, T
is move-insertable
into X
means that the following expression is well-formed: allocator_traits<A>::construct(m, p, rv)
copy-insertable: T
provides a constructor that takes an lvalue or rvalue of type (possibly const
) T
. More precisely, T
is copy-insertable
into X
means that the following expression is well-formed: allocator_traits<A>::construct(m, p, v)
move-assignable: T
provides an assignment operator that takes an rvalue of type (non-const
) T
.
copy-assignable: T
provides an assignment operator that takes an lvalue or rvalue of type (possibly const
) T
.
emplace-constructible: T
is emplace-constructible
into X
from args
means that the following expression is well-formed: allocator_traits<A>::construct(m, p, args)
erasable: T
provides a destructor. More precisely, T
is erasable
from X
means that the following expression is well-formed: allocator_traits<A>::destroy(m, p)
equality-comparable: The type provides an equality-comparison operator that defines an equivalence relationship and is both reflexive and transitive.
Key Comparison
The type supplied as a map's COMPARATOR
template parameter determines how that map will order elements. In particular, the COMPARATOR
type must induce a strict weak ordering on objects of type KEY
. The COMPARATOR
parameter defaults to std::less<KEY>
when not supplied in an instantiation of map
. Note that the COMPARATOR
type must be copy-constructible.
The C++11 standard does not require that the function-call operator provided by COMPARATOR
functors be const
-qualified. However, there is a suggestion for C++17 that this is an oversight in the standard, and that const
-qualification will be required in the future. Keep this in mind when opting to use an alternative to the default COMPARATOR
.
Memory Allocation
The type supplied as a map's ALLOCATOR
template parameter determines how that map will allocate memory. The map
template supports allocators meeting the requirements of the C++11 standard [allocator.requirements]. In addition, map
supports scoped-allocators derived from the bslma::Allocator
memory allocation protocol. Clients intending to use bslma
-style allocators should use the template's default ALLOCATOR
type: The default type for the ALLOCATOR
template parameter, bsl::allocator
, provides a C++11 standard-compatible adapter for a bslma::Allocator
object.
bslma-Style Allocators
If the (template parameter) type ALLOCATOR
of a map
instantiation' is bsl::allocator
, then objects of that map type will conform to the standard behavior of a bslma
-allocator-enabled type. Such a map accepts an optional bslma::Allocator
argument at construction. If the address of a bslma::Allocator
object is explicitly supplied at construction, it is used to supply memory for the map throughout its lifetime; otherwise, the map will use the default allocator installed at the time of the map's construction (see bslma_default ). In addition to directly allocating memory from the indicated bslma::Allocator
, a map supplies that allocator's address to the constructors of contained objects of the (template parameter) type KEY
and VALUE
, if respectively, the types define the bslma::UsesBslmaAllocator
trait.
Operations
This section describes the run-time complexity of operations on instances of map
:
Legend
------
'K' - (template parameter) type 'KEY' of the map
'V' - (template parameter) type 'VALUE' of the map
'a', 'b' - two distinct objects of type 'map<K, V>'
'rv' - modifiable rvalue of type 'map<K, V>'
'n', 'm' - number of elements in 'a' and 'b', respectively
'value_type' - 'pair<const K, V>'
'c' - comparator providing an ordering for objects of type 'K'
'al - STL-style memory allocator
'i1', 'i2' - two iterators defining a sequence of 'value_type' objects
'k' - object of type 'K'
'v' - object of type 'V'
'vt' - object of type 'value_type'
'rvt' - modifiable rvalue of type 'value_type'
'p1', 'p2' - two 'const_iterator's belonging to 'a'
distance(i1,i2) - number of elements in the range '[i1 .. i2)'
+----------------------------------------------------+--------------------+
| Operation | Complexity |
+====================================================+====================+
| map<K, V> a; (default construction) | O[1] |
| map<K, V> a(al); | |
| map<K, V> a(c, al); | |
+----------------------------------------------------+--------------------+
| map<K, V> a(rv); (move construction) | O[1] if 'a' and |
| map<K, V> a(rv, al); | 'rv' use the same |
| | allocator, |
| | O[n] otherwise |
+----------------------------------------------------+--------------------+
| map<K, V> a(b); (copy construction) | O[n] |
| map<K, V> a(b, al); | |
+----------------------------------------------------+--------------------+
| map<K, V> a(i1, i2); | O[N] if [i1 .. i2) |
| map<K, V> a(i1, i2, al); | is sorted with |
| map<K, V> a(i1, i2, c, al); | 'a.value_comp()', |
| | O[N * log(N)] |
| | otherwise, where N |
| | is distance(i1,i2) |
+----------------------------------------------------+--------------------+
| a.~map<K, V>(); (destruction) | O[n] |
+----------------------------------------------------+--------------------+
| a = rv; (move assignment) | O[1] if 'a' and |
| | 'rv' use the same |
| | allocator, |
| | O[n] otherwise |
+----------------------------------------------------+--------------------+
| a = b; (copy assignment) | O[n] |
+----------------------------------------------------+--------------------+
| a.begin(), a.end(), a.cbegin(), a.cend(), | O[1] |
| a.rbegin(), a.rend(), a.crbegin(), a.crend() | |
+----------------------------------------------------+--------------------+
| a == b, a != b | O[n] |
+----------------------------------------------------+--------------------+
| a < b, a <= b, a > b, a >= b | O[n] |
+----------------------------------------------------+--------------------+
| a.swap(b), swap(a, b) | O[1] if 'a' and |
| | 'b' use the same |
| | allocator, |
| | O[n + m] otherwise |
+----------------------------------------------------+--------------------+
| a.size() | O[1] |
+----------------------------------------------------+--------------------+
| a.max_size() | O[1] |
+----------------------------------------------------+--------------------+
| a.empty() | O[1] |
+----------------------------------------------------+--------------------+
| get_allocator() | O[1] |
+----------------------------------------------------+--------------------+
| a[k] | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.at(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.insert(vt) | O[log(n)] |
| a.insert(rvt) | |
| a.emplace(Args&&...) | |
+----------------------------------------------------+--------------------+
| a.insert(p1, vt) | amortized constant |
| a.insert(p1, rvt) | if the value is |
| a.emplace(p1, Args&&...) | inserted right |
| | before p1, |
| | O[log(n)] |
| | otherwise |
+----------------------------------------------------+--------------------+
| a.insert(i1, i2) | O[log(N) * |
| | distance(i1,i2)] |
| | |
| | where N is |
| | n + distance(i1,i2)|
+----------------------------------------------------+--------------------+
| a.erase(p1) | amortized constant |
+----------------------------------------------------+--------------------+
| a.erase(k) | O[log(n) + |
| | a.count(k)] |
+----------------------------------------------------+--------------------+
| a.erase(p1, p2) | O[log(n) + |
| | distance(p1, p2)] |
+----------------------------------------------------+--------------------+
| a.erase(p1, p2) | O[log(n) + |
| | distance(p1, p2)] |
+----------------------------------------------------+--------------------+
| a.clear() | O[n] |
+----------------------------------------------------+--------------------+
| a.contains(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.key_comp() | O[1] |
+----------------------------------------------------+--------------------+
| a.value_comp() | O[1] |
+----------------------------------------------------+--------------------+
| a.find(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.count(k) | O[log(n) + |
| | a.count(k)] |
+----------------------------------------------------+--------------------+
| a.lower_bound(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.upper_bound(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
| a.equal_range(k) | O[log(n)] |
+----------------------------------------------------+--------------------+
Usage
In this section we show intended use of this component.
Example 1: Creating a Trade Matching System
In this example, we will utilize bsl::map
to define and implement a class, TradeMatcher
, that provides a simple trade matching system for a single stock. The manipulators of TradeMatcher
will allow clients to place buy orders and sell orders, and the accessors of TradeMatcher
will allow clients to retrieve active orders and past executions.
First, we define the public interface for TradeMatcher
:
Here, we create two type aliases, SellOrdersMap
and BuyOrdersMap
, for two bsl::map
instantiations that maps the price of an order (type double
) to the quantity of the order (type int
). SellOrdersMap
uses the default bsl::less
comparator to store the sequence of sell orders in ascending price order. BuyOrdersMap
uses the bsl::greater
comparator to store the sequence of buy orders in descending price order. Also note that we use the default ALLOCATOR
template parameter for both aliases as we intend to provide memory with bslma
-style allocators:
SellOrdersMap d_sellOrders;
BuyOrdersMap d_buyOrders;
private:
TradeMatcher& operator=(const TradeMatcher&);
TradeMatcher(const TradeMatcher&);
public:
typedef SellOrdersMap::const_iterator SellOrdersConstIterator;
typedef BuyOrdersMap::const_iterator BuyOrdersConstIterator;
void placeBuyOrder(double price, int numShares);
void placeSellOrder(double price, int numShares);
SellOrdersConstIterator beginSellOrders() const;
SellOrdersConstIterator endSellOrders() const;
BuyOrdersConstIterator beginBuyOrders() const;
BuyOrdersConstIterator endBuyOrders() const;
};
Definition bslstl_map.h:619
Definition bslma_allocator.h:457
Now, we define the implementations methods of the TradeMatcher
class:
: d_sellOrders(basicAllocator)
, d_buyOrders(basicAllocator)
{
}
Notice that, on construction, we pass the contained bsl::map
objects the bsl::Allocator
supplied at construction'.
void TradeMatcher::placeBuyOrder(double price, int numShares)
{
SellOrdersMap::iterator itr = d_sellOrders.begin();
while (numShares && itr != d_sellOrders.upper_bound(price)) {
if (itr->second > numShares) {
itr->second -= numShares;
numShares = 0;
break;
}
itr = d_sellOrders.erase(itr);
numShares -= itr->second;
}
if (numShares > 0) {
d_buyOrders[price] += numShares;
}
}
void TradeMatcher::placeSellOrder(double price, int numShares)
{
BuyOrdersMap::iterator itr = d_buyOrders.begin();
while (numShares && itr != d_buyOrders.upper_bound(price)) {
if (itr->second > numShares) {
itr->second -= numShares;
numShares = 0;
break;
}
itr = d_buyOrders.erase(itr);
numShares -= itr->second;
}
if (numShares > 0) {
d_sellOrders[price] += numShares;
}
}
TradeMatcher::SellOrdersConstIterator TradeMatcher::beginSellOrders() const
{
return d_sellOrders.begin();
}
TradeMatcher::SellOrdersConstIterator TradeMatcher::endSellOrders() const
{
return d_sellOrders.end();
}
TradeMatcher::BuyOrdersConstIterator TradeMatcher::beginBuyOrders() const
{
return d_buyOrders.begin();
}
TradeMatcher::BuyOrdersConstIterator TradeMatcher::endBuyOrders() const
{
return d_buyOrders.end();
}
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804