From dab7140405a50a57435ed8dfec0a0feadb26297c Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 7 May 2019 01:12:34 +0700 Subject: [PATCH 01/11] add support for containers without ctor with allocator argument --- headers/flat_hpp/flat_map.hpp | 4 +++- headers/flat_hpp/flat_set.hpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index e33244a..cca641a 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -87,12 +87,14 @@ namespace flat_hpp std::is_same::value, "Container::allocator_type must be same type as allocator_type"); public: + flat_map() = default; + explicit flat_map( const Allocator& a) : data_(a) {} explicit flat_map( - const Compare& c = Compare(), + const Compare& c, const Allocator& a = Allocator()) : data_(a) , compare_(c) {} diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index 5feda61..ffec69e 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -56,12 +56,14 @@ namespace flat_hpp std::is_same::value, "Container::allocator_type must be same type as allocator_type"); public: + flat_set() = default; + explicit flat_set( const Allocator& a) : data_(a) {} explicit flat_set( - const Compare& c = Compare(), + const Compare& c, const Allocator& a = Allocator()) : data_(a) , compare_(c) {} From 06d4916d46af38f5e7bc52667721e7c7a5e762f1 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 7 May 2019 01:47:20 +0700 Subject: [PATCH 02/11] add extended copy ctors --- headers/flat_hpp/flat_map.hpp | 8 ++++++++ headers/flat_hpp/flat_set.hpp | 8 ++++++++ untests/flat_map_tests.cpp | 7 +++++++ untests/flat_set_tests.cpp | 7 +++++++ 4 files changed, 30 insertions(+) diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index cca641a..90306f9 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -135,6 +135,14 @@ namespace flat_hpp insert(ilist); } + flat_map(flat_map&& other, const Allocator& a) + : data_(std::move(other.data_), a) + , compare_(std::move(other.compare_)) {} + + flat_map(const flat_map& other, const Allocator& a) + : data_(other.data_, a) + , compare_(other.compare_) {} + flat_map(flat_map&& other) = default; flat_map(const flat_map& other) = default; diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index ffec69e..7b0dd73 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -104,6 +104,14 @@ namespace flat_hpp insert(ilist); } + flat_set(flat_set&& other, const Allocator& a) + : data_(std::move(other.data_), a) + , compare_(std::move(other.compare_)) {} + + flat_set(const flat_set& other, const Allocator& a) + : data_(other.data_, a) + , compare_(other.compare_) {} + flat_set(flat_set&& other) = default; flat_set(const flat_set& other) = default; diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index b8b56ef..2d6b976 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -177,6 +177,13 @@ TEST_CASE("flat_map") { auto s2 = std::move(s1); REQUIRE(s1.empty()); REQUIRE(s2 == map_t{{0,1}, {1,2}}); + auto s3 = map_t(s2, alloc_t(42)); + REQUIRE(s2 == s3); + REQUIRE(s2.get_allocator().i == 0); + REQUIRE(s3.get_allocator().i == 42); + auto s4 = map_t(std::move(s3), alloc_t(21)); + REQUIRE(s3.empty()); + REQUIRE(s4 == map_t{{0,1}, {1,2}}); } { diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index bbc0435..ea6b6af 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -161,6 +161,13 @@ TEST_CASE("flat_set") { auto s2 = std::move(s1); REQUIRE(s1.empty()); REQUIRE(s2 == set_t{0,1,2}); + auto s3 = set_t(s2, alloc_t(42)); + REQUIRE(s2 == s3); + REQUIRE(s2.get_allocator().i == 0); + REQUIRE(s3.get_allocator().i == 42); + auto s4 = set_t(std::move(s3), alloc_t(21)); + REQUIRE(s3.empty()); + REQUIRE(s4 == set_t{0,1,2}); } { From 073789c76726e2ce6c26a7acaa766aa6ba85320a Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 7 May 2019 03:10:20 +0700 Subject: [PATCH 03/11] add dummy benchmark project --- CMakeLists.txt | 7 ++++++- unbench/CMakeLists.txt | 24 ++++++++++++++++++++++++ unbench/flat_map_bench.cpp | 21 +++++++++++++++++++++ unbench/flat_set_bench.cpp | 21 +++++++++++++++++++++ untests/CMakeLists.txt | 6 ++++-- 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 unbench/CMakeLists.txt create mode 100644 unbench/flat_map_bench.cpp create mode 100644 unbench/flat_set_bench.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 94c0bc8..c62b32d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,14 @@ project(flat.hpp) add_library(${PROJECT_NAME} INTERFACE) target_include_directories(${PROJECT_NAME} INTERFACE headers) target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_14) -add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) if(BUILD_AS_STANDALONE) + option(BUILD_WITH_UNBENCH "Build with benchmarks" OFF) + if(BUILD_WITH_UNBENCH) + enable_testing() + add_subdirectory(unbench) + endif() + option(BUILD_WITH_UNTESTS "Build with unit tests" ON) if(BUILD_WITH_UNTESTS) enable_testing() diff --git a/unbench/CMakeLists.txt b/unbench/CMakeLists.txt new file mode 100644 index 0000000..b077be1 --- /dev/null +++ b/unbench/CMakeLists.txt @@ -0,0 +1,24 @@ +# 3.11 version is required for `FetchContent` +cmake_minimum_required(VERSION 3.11 FATAL_ERROR) + +project(flat.hpp.unbench) + +set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) + +include(FetchContent) +FetchContent_Declare( + gbench + GIT_REPOSITORY https://github.com/google/benchmark) + +FetchContent_GetProperties(gbench) +if(NOT gbench_POPULATED) + FetchContent_Populate(gbench) + add_subdirectory(${gbench_SOURCE_DIR} ${gbench_BINARY_DIR}) +endif() + +file(GLOB UNBENCH_SOURCES "*.cpp" "*.hpp") +add_executable(${PROJECT_NAME} ${UNBENCH_SOURCES}) +target_link_libraries(${PROJECT_NAME} + benchmark_main + flat.hpp) +add_test(${PROJECT_NAME} ${PROJECT_NAME}) diff --git a/unbench/flat_map_bench.cpp b/unbench/flat_map_bench.cpp new file mode 100644 index 0000000..c3c9efe --- /dev/null +++ b/unbench/flat_map_bench.cpp @@ -0,0 +1,21 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include + +#include +using namespace flat_hpp; + +namespace +{ + void flat_map_default_ctor(benchmark::State& state) { + for ( auto _ : state ) { + flat_map s0; + } + } +} + +BENCHMARK(flat_map_default_ctor); diff --git a/unbench/flat_set_bench.cpp b/unbench/flat_set_bench.cpp new file mode 100644 index 0000000..fb1232b --- /dev/null +++ b/unbench/flat_set_bench.cpp @@ -0,0 +1,21 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include + +#include +using namespace flat_hpp; + +namespace +{ + void flat_set_default_ctor(benchmark::State& state) { + for ( auto _ : state ) { + flat_set s0; + } + } +} + +BENCHMARK(flat_set_default_ctor); diff --git a/untests/CMakeLists.txt b/untests/CMakeLists.txt index 157b777..735fbe1 100644 --- a/untests/CMakeLists.txt +++ b/untests/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.11 FATAL_ERROR) project(flat.hpp.untests) +set(CATCH_BUILD_TESTING OFF CACHE BOOL "" FORCE) + include(FetchContent) FetchContent_Declare( catch2 @@ -17,6 +19,6 @@ endif() file(GLOB UNTESTS_SOURCES "*.cpp" "*.hpp") add_executable(${PROJECT_NAME} ${UNTESTS_SOURCES}) target_link_libraries(${PROJECT_NAME} - Catch2::Catch2 - flat.hpp::flat.hpp) + Catch2 + flat.hpp) add_test(${PROJECT_NAME} ${PROJECT_NAME}) From ecb354bfcecada41fc1e39cdf4ce2d0346ea9208 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 7 May 2019 04:17:33 +0700 Subject: [PATCH 04/11] fix clang 3.8 compilation --- headers/flat_hpp/flat_map.hpp | 2 +- headers/flat_hpp/flat_set.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index 90306f9..f914b62 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -87,7 +87,7 @@ namespace flat_hpp std::is_same::value, "Container::allocator_type must be same type as allocator_type"); public: - flat_map() = default; + flat_map() {} explicit flat_map( const Allocator& a) diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index 7b0dd73..95ab531 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -56,7 +56,7 @@ namespace flat_hpp std::is_same::value, "Container::allocator_type must be same type as allocator_type"); public: - flat_set() = default; + flat_set() {} explicit flat_set( const Allocator& a) From a8bcd40cddb1b987e8efd0351b90bf1d7abb1476 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Wed, 8 May 2019 07:36:03 +0700 Subject: [PATCH 05/11] add basic bench plotter and simple insert bench --- scripts/bench_drawer.py | 116 ++++++++++++++++++++++++++++++++++ scripts/bench_map_insert.sh | 8 +++ scripts/bench_set_insert.sh | 8 +++ unbench/CMakeLists.txt | 16 +++++ unbench/bench_base.hpp | 119 +++++++++++++++++++++++++++++++++++ unbench/flat_map_bench.cpp | 21 ------- unbench/flat_set_bench.cpp | 21 ------- unbench/map_insert_bench.cpp | 80 +++++++++++++++++++++++ unbench/set_insert_bench.cpp | 80 +++++++++++++++++++++++ 9 files changed, 427 insertions(+), 42 deletions(-) create mode 100755 scripts/bench_drawer.py create mode 100755 scripts/bench_map_insert.sh create mode 100755 scripts/bench_set_insert.sh create mode 100644 unbench/bench_base.hpp delete mode 100644 unbench/flat_map_bench.cpp delete mode 100644 unbench/flat_set_bench.cpp create mode 100644 unbench/map_insert_bench.cpp create mode 100644 unbench/set_insert_bench.cpp diff --git a/scripts/bench_drawer.py b/scripts/bench_drawer.py new file mode 100755 index 0000000..0a15081 --- /dev/null +++ b/scripts/bench_drawer.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +"""Script to visualize google-benchmark output""" +from __future__ import print_function +import argparse +import sys +import logging +import pandas as pd +import matplotlib.pyplot as plt + +logging.basicConfig(format='[%(levelname)s] %(message)s') + +METRICS = ['real_time', 'cpu_time', 'bytes_per_second', 'items_per_second'] +TRANSFORMS = { + '': lambda x: x, + 'inverse': lambda x: 1.0 / x +} + + +def get_default_ylabel(args): + """Compute default ylabel for commandline args""" + label = '' + if args.transform == '': + label = args.metric + else: + label = args.transform + '(' + args.metric + ')' + if args.relative_to is not None: + label += ' relative to %s' % args.relative_to + return label + + +def parse_args(): + """Parse commandline arguments""" + parser = argparse.ArgumentParser( + description='Visualize google-benchmark output') + parser.add_argument( + '-f', metavar='FILE', type=argparse.FileType('r'), default=sys.stdin, + dest='file', help='path to file containing the csv benchmark data') + parser.add_argument( + '-m', metavar='METRIC', choices=METRICS, default=METRICS[0], dest='metric', + help='metric to plot on the y-axis, valid choices are: %s' % ', '.join(METRICS)) + parser.add_argument( + '-t', metavar='TRANSFORM', choices=TRANSFORMS.keys(), default='', + help='transform to apply to the chosen metric, valid choices are: %s' + % ', '.join(list(TRANSFORMS)), dest='transform') + parser.add_argument( + '-r', metavar='RELATIVE_TO', type=str, default=None, + dest='relative_to', help='plot metrics relative to this label') + parser.add_argument( + '--xlabel', type=str, default='input size', help='label of the x-axis') + parser.add_argument( + '--ylabel', type=str, help='label of the y-axis') + parser.add_argument( + '--title', type=str, default='', help='title of the plot') + parser.add_argument( + '--logx', action='store_true', help='plot x-axis on a logarithmic scale') + parser.add_argument( + '--logy', action='store_true', help='plot y-axis on a logarithmic scale') + + args = parser.parse_args() + if args.ylabel is None: + args.ylabel = get_default_ylabel(args) + return args + + +def read_data(args): + """Read and process dataframe using commandline args""" + try: + data = pd.read_csv(args.file, usecols=['name', args.metric]) + except ValueError: + msg = 'Could not parse the benchmark data. Did you forget "--benchmark_format=csv"?' + logging.error(msg) + exit(1) + data['label'] = data['name'].apply(lambda x: x.split('/')[0]) + data['input'] = data['name'].apply(lambda x: int(x.split('/')[1])) + data[args.metric] = data[args.metric].apply(TRANSFORMS[args.transform]) + return data + + +def plot_groups(label_groups, args): + """Display the processed data""" + for label, group in label_groups.items(): + plt.plot(group['input'], group[args.metric], label=label) + if args.logx: + plt.xscale('log') + if args.logy: + plt.yscale('log') + plt.xlabel(args.xlabel) + plt.ylabel(args.ylabel) + plt.title(args.title) + plt.legend() + plt.show() + + +def main(): + """Entry point of the program""" + args = parse_args() + data = read_data(args) + label_groups = {} + for label, group in data.groupby('label'): + label_groups[label] = group.set_index('input', drop=False) + if args.relative_to is not None: + try: + baseline = label_groups[args.relative_to][args.metric].copy() + except KeyError, key: + msg = 'Key %s is not present in the benchmark output' + logging.error(msg, str(key)) + exit(1) + + if args.relative_to is not None: + for label in label_groups: + label_groups[label][args.metric] /= baseline + plot_groups(label_groups, args) + + +if __name__ == '__main__': + main() diff --git a/scripts/bench_map_insert.sh b/scripts/bench_map_insert.sh new file mode 100755 index 0000000..5333e9f --- /dev/null +++ b/scripts/bench_map_insert.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_map_insert --benchmark_format=csv > benchmark_map_insert.csv +../scripts/bench_drawer.py -f benchmark_map_insert.csv diff --git a/scripts/bench_set_insert.sh b/scripts/bench_set_insert.sh new file mode 100755 index 0000000..1e8d850 --- /dev/null +++ b/scripts/bench_set_insert.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_set_insert --benchmark_format=csv > benchmark_set_insert.csv +../scripts/bench_drawer.py -f benchmark_set_insert.csv diff --git a/unbench/CMakeLists.txt b/unbench/CMakeLists.txt index b077be1..acf0647 100644 --- a/unbench/CMakeLists.txt +++ b/unbench/CMakeLists.txt @@ -3,6 +3,17 @@ cmake_minimum_required(VERSION 3.11 FATAL_ERROR) project(flat.hpp.unbench) +# +# boost +# + +find_package(Boost REQUIRED + COMPONENTS container) + +# +# google benchmark +# + set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE) include(FetchContent) @@ -16,9 +27,14 @@ if(NOT gbench_POPULATED) add_subdirectory(${gbench_SOURCE_DIR} ${gbench_BINARY_DIR}) endif() +# +# benchmark executable +# + file(GLOB UNBENCH_SOURCES "*.cpp" "*.hpp") add_executable(${PROJECT_NAME} ${UNBENCH_SOURCES}) target_link_libraries(${PROJECT_NAME} + Boost::container benchmark_main flat.hpp) add_test(${PROJECT_NAME} ${PROJECT_NAME}) diff --git a/unbench/bench_base.hpp b/unbench/bench_base.hpp new file mode 100644 index 0000000..cf53719 --- /dev/null +++ b/unbench/bench_base.hpp @@ -0,0 +1,119 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace flat_hpp_unbench +{ + struct vec2 { + int x = 0; + int y = 0; + + vec2(int v) noexcept + : x(v), y(v) {} + + bool operator<(const vec2& o) const noexcept { + return + (x < o.x) || + (x == o.x && y < o.y); + } + + bool operator==(const vec2& o) const noexcept { + return x == o.x + && y == o.y; + } + + std::size_t hash() const noexcept { + std::hash hasher; + std::size_t seed = hasher(x); + seed ^= hasher(y) + 0x9e3779b9 + (seed<<6) + (seed>>2); + return seed; + } + }; + + struct vec4 { + int x = 0; + int y = 0; + int z = 0; + int w = 0; + + vec4(int v) noexcept + : x(v), y(v), z(v), w(v) {} + + bool operator<(const vec4& o) const noexcept { + return + (x < o.x) || + (x == o.x && y < o.y) || + (x == o.x && y == o.y && z < o.z) || + (x == o.x && y == o.y && z == o.z && w < o.w); + } + + bool operator==(const vec4& o) const noexcept { + return x == o.x + && y == o.y + && z == o.z + && w == o.w; + } + + std::size_t hash() const noexcept { + std::hash hasher; + std::size_t seed = hasher(x); + seed ^= hasher(y) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= hasher(z) + 0x9e3779b9 + (seed<<6) + (seed>>2); + seed ^= hasher(w) + 0x9e3779b9 + (seed<<6) + (seed>>2); + return seed; + } + }; + + inline void generate_random_vector(std::size_t n, std::vector& v) { + std::mt19937 engine(n); + std::uniform_int_distribution dist; + + std::vector nv(n); + for ( std::size_t i = 0; i < n; ++i ) { + nv[i] = dist(engine); + } + + v = std::move(nv); + } + + inline double min_bench_statistics(const std::vector& v) { + return v.empty() + ? 0.0 + : *(std::min_element(v.begin(), v.end())); + }; +} + +namespace std +{ + template <> + struct hash { + size_t operator()(const flat_hpp_unbench::vec2& v) const { + return v.hash(); + } + }; + + template <> + struct hash { + size_t operator()(const flat_hpp_unbench::vec4& v) const { + return v.hash(); + } + }; +} diff --git a/unbench/flat_map_bench.cpp b/unbench/flat_map_bench.cpp deleted file mode 100644 index c3c9efe..0000000 --- a/unbench/flat_map_bench.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* - * This file is part of the "https://github.com/blackmatov/flat.hpp" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) - ******************************************************************************/ - -#include - -#include -using namespace flat_hpp; - -namespace -{ - void flat_map_default_ctor(benchmark::State& state) { - for ( auto _ : state ) { - flat_map s0; - } - } -} - -BENCHMARK(flat_map_default_ctor); diff --git a/unbench/flat_set_bench.cpp b/unbench/flat_set_bench.cpp deleted file mode 100644 index fb1232b..0000000 --- a/unbench/flat_set_bench.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/******************************************************************************* - * This file is part of the "https://github.com/blackmatov/flat.hpp" - * For conditions of distribution and use, see copyright notice in LICENSE.md - * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) - ******************************************************************************/ - -#include - -#include -using namespace flat_hpp; - -namespace -{ - void flat_set_default_ctor(benchmark::State& state) { - for ( auto _ : state ) { - flat_set s0; - } - } -} - -BENCHMARK(flat_set_default_ctor); diff --git a/unbench/map_insert_bench.cpp b/unbench/map_insert_bench.cpp new file mode 100644 index 0000000..87ba572 --- /dev/null +++ b/unbench/map_insert_bench.cpp @@ -0,0 +1,80 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#include + +namespace +{ + template < typename Value > + void flat_map_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + flat_map s; + for ( auto e : v ) { + s.emplace(e, e); + } + } + } + + template < typename Value > + void boost_flat_map_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + boost::container::flat_map s; + for ( auto e : v ) { + s.emplace(e, e); + } + } + } + + template < typename Value > + void std_map_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + std::map s; + for ( auto e : v ) { + s.emplace(e, e); + } + } + } + + template < typename Value > + void std_unordered_map_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + std::unordered_map s; + for ( auto e : v ) { + s.emplace(e, e); + } + } + } +} + +BENCHMARK_TEMPLATE(flat_map_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(boost_flat_map_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_map_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_map_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); diff --git a/unbench/set_insert_bench.cpp b/unbench/set_insert_bench.cpp new file mode 100644 index 0000000..f9296e4 --- /dev/null +++ b/unbench/set_insert_bench.cpp @@ -0,0 +1,80 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#include + +namespace +{ + template < typename Key > + void flat_set_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + flat_set s; + for ( auto e : v ) { + s.emplace(e); + } + } + } + + template < typename Key > + void boost_flat_set_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + boost::container::flat_set s; + for ( auto e : v ) { + s.emplace(e); + } + } + } + + template < typename Key > + void std_set_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + std::set s; + for ( auto e : v ) { + s.emplace(e); + } + } + } + + template < typename Key > + void std_unordered_set_insert(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + for ( auto _ : state ) { + std::unordered_set s; + for ( auto e : v ) { + s.emplace(e); + } + } + } +} + +BENCHMARK_TEMPLATE(flat_set_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(boost_flat_set_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_set_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_set_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); From 916ba1bd7f66da14e0b21d8d20dd676b6d6eb67d Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 00:02:24 +0700 Subject: [PATCH 06/11] optional boost bench --- unbench/CMakeLists.txt | 14 +++++++++++--- unbench/map_insert_bench.cpp | 14 ++++++++++---- unbench/set_insert_bench.cpp | 14 ++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/unbench/CMakeLists.txt b/unbench/CMakeLists.txt index acf0647..f257e35 100644 --- a/unbench/CMakeLists.txt +++ b/unbench/CMakeLists.txt @@ -7,8 +7,8 @@ project(flat.hpp.unbench) # boost # -find_package(Boost REQUIRED - COMPONENTS container) +find_package(Boost + OPTIONAL_COMPONENTS container) # # google benchmark @@ -33,8 +33,16 @@ endif() file(GLOB UNBENCH_SOURCES "*.cpp" "*.hpp") add_executable(${PROJECT_NAME} ${UNBENCH_SOURCES}) + target_link_libraries(${PROJECT_NAME} - Boost::container benchmark_main flat.hpp) + +if(Boost_CONTAINER_FOUND) + target_link_libraries(${PROJECT_NAME} + Boost::container) + target_compile_definitions(${PROJECT_NAME} + PRIVATE BOOST_CONTAINER_FOUND) +endif() + add_test(${PROJECT_NAME} ${PROJECT_NAME}) diff --git a/unbench/map_insert_bench.cpp b/unbench/map_insert_bench.cpp index 87ba572..3343f41 100644 --- a/unbench/map_insert_bench.cpp +++ b/unbench/map_insert_bench.cpp @@ -10,7 +10,9 @@ using namespace flat_hpp_unbench; #include using namespace flat_hpp; -#include +#ifdef BOOST_CONTAINER_FOUND +# include +#endif namespace { @@ -26,6 +28,7 @@ namespace } } +#ifdef BOOST_CONTAINER_FOUND template < typename Value > void boost_flat_map_insert(benchmark::State& state) { std::vector v; @@ -37,6 +40,7 @@ namespace } } } +#endif template < typename Value > void std_map_insert(benchmark::State& state) { @@ -67,9 +71,11 @@ BENCHMARK_TEMPLATE(flat_map_insert, vec4) ->ComputeStatistics("min", min_bench_statistics) ->DenseRange(1,401,50); -BENCHMARK_TEMPLATE(boost_flat_map_insert, vec4) - ->ComputeStatistics("min", min_bench_statistics) - ->DenseRange(1,401,50); +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_map_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif BENCHMARK_TEMPLATE(std_map_insert, vec4) ->ComputeStatistics("min", min_bench_statistics) diff --git a/unbench/set_insert_bench.cpp b/unbench/set_insert_bench.cpp index f9296e4..7d888e4 100644 --- a/unbench/set_insert_bench.cpp +++ b/unbench/set_insert_bench.cpp @@ -10,7 +10,9 @@ using namespace flat_hpp_unbench; #include using namespace flat_hpp; -#include +#ifdef BOOST_CONTAINER_FOUND +# include +#endif namespace { @@ -26,6 +28,7 @@ namespace } } +#ifdef BOOST_CONTAINER_FOUND template < typename Key > void boost_flat_set_insert(benchmark::State& state) { std::vector v; @@ -37,6 +40,7 @@ namespace } } } +#endif template < typename Key > void std_set_insert(benchmark::State& state) { @@ -67,9 +71,11 @@ BENCHMARK_TEMPLATE(flat_set_insert, vec4) ->ComputeStatistics("min", min_bench_statistics) ->DenseRange(1,401,50); -BENCHMARK_TEMPLATE(boost_flat_set_insert, vec4) - ->ComputeStatistics("min", min_bench_statistics) - ->DenseRange(1,401,50); +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_set_insert, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif BENCHMARK_TEMPLATE(std_set_insert, vec4) ->ComputeStatistics("min", min_bench_statistics) From 4d2fdff3b2ceccc05bf8f82e68d83dda5a92bf57 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 02:43:47 +0700 Subject: [PATCH 07/11] remove Allocator template param --- README.md | 188 +++++++++++++++++----------------- headers/flat_hpp/flat_map.hpp | 137 ++++++++++++------------- headers/flat_hpp/flat_set.hpp | 113 +++++++++----------- untests/flat_map_tests.cpp | 16 +-- untests/flat_set_tests.cpp | 14 +-- 5 files changed, 214 insertions(+), 254 deletions(-) diff --git a/README.md b/README.md index 506af96..8f66e97 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,7 @@ target_link_libraries(your_project_target flat.hpp) ```cpp template < typename Key , typename Compare = std::less - , typename Allocator = std::allocator - , typename Container = std::vector > + , typename Container = std::vector > class flat_set; ``` @@ -71,7 +70,6 @@ class flat_set; | `difference_type` | `Container::difference_type` | | `key_compare` | `Compare` | | `value_compare` | `Compare` | -| `allocator_type` | `Allocator` | | `container_type` | `Container` | | `reference` | `Container::reference` | | `const_reference` | `Container::const_reference` | @@ -85,43 +83,51 @@ class flat_set; ### Member functions ```cpp -explicit flat_set( - const Allocator& a); +flat_set(); -explicit flat_set( - const Compare& c = Compare(), - const Allocator& a = Allocator()); +explicit flat_set(const Compare& c); + +template < typename Allocator > +explicit flat_set(const Allocator& a); + +template < typename Allocator > +flat_set(const Compare& c, const Allocator& a); template < typename InputIter > -flat_set( - InputIter first, - InputIter last, - const Allocator& a); +flat_set(InputIter first, InputIter last); template < typename InputIter > -flat_set( - InputIter first, - InputIter last, - const Compare& c = Compare(), - const Allocator& a = Allocator()); +flat_set(InputIter first, InputIter last, const Compare& c); -flat_set( - std::initializer_list ilist, - const Allocator& a); +template < typename InputIter, typename Allocator > +flat_set(InputIter first, InputIter last, const Allocator& a); -flat_set( - std::initializer_list ilist, - const Compare& c = Compare(), - const Allocator& a = Allocator()); +template < typename InputIter, typename Allocator > +flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a); + +flat_set(std::initializer_list ilist); + +flat_set(std::initializer_list ilist, const Compare& c); + +template < typename Allocator > +flat_set(std::initializer_list ilist, const Allocator& a); + +template < typename Allocator > +flat_set(std::initializer_list ilist, const Compare& c, const Allocator& a); + +template < typename Allocator > +flat_set(flat_set&& other, const Allocator& a); + +template < typename Allocator > +flat_set(const flat_set& other, const Allocator& a); flat_set(flat_set&& other); -flat_set(const flat_set& other) +flat_set(const flat_set& other); flat_set& operator=(flat_set&& other); flat_set& operator=(const flat_set& other); -flat_set& operator=(std::initializer_list ilist); -allocator_type get_allocator() const; +flat_set& operator=(std::initializer_list ilist); ``` ### Iterators @@ -211,59 +217,52 @@ value_compare value_comp() const; ```cpp template < typename Key , typename Compare - , typename Allocator , typename Container > void swap( - flat_set& l, - flat_set& r); + flat_set& l, + flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator==( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator!=( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator<( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator>( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator<=( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator>=( - const flat_set& l, - const flat_set& r); + const flat_set& l, + const flat_set& r); ``` ## Flat Map @@ -272,8 +271,7 @@ bool operator>=( template < typename Key , typename Value , typename Compare = std::less - , typename Allocator = std::allocator> - , typename Container = std::vector, Allocator> > + , typename Container = std::vector> > class flat_map; ``` @@ -287,7 +285,6 @@ class flat_map; | `size_type` | `Container::size_type` | | `difference_type` | `Container::difference_type` | | `key_compare` | `Compare` | -| `allocator_type` | `Allocator` | | `container_type` | `Container` | | `reference` | `Container::reference` | | `const_reference` | `Container::const_reference` | @@ -307,43 +304,51 @@ class value_compare; ### Member functions ```cpp -explicit flat_map( - const Allocator& a); +flat_map(); -explicit flat_map( - const Compare& c = Compare(), - const Allocator& a = Allocator()); +explicit flat_map(const Compare& c); + +template < typename Allocator > +explicit flat_map(const Allocator& a); + +template < typename Allocator > +flat_map(const Compare& c, const Allocator& a); template < typename InputIter > -flat_map( - InputIter first, - InputIter last, - const Allocator& a); +flat_map(InputIter first, InputIter last); template < typename InputIter > -flat_map( - InputIter first, - InputIter last, - const Compare& c = Compare(), - const Allocator& a = Allocator()); +flat_map(InputIter first, InputIter last, const Compare& c); -flat_map( - std::initializer_list ilist, - const Allocator& a); +template < typename InputIter, typename Allocator > +flat_map(InputIter first, InputIter last, const Allocator& a); -flat_map( - std::initializer_list ilist, - const Compare& c = Compare(), - const Allocator& a = Allocator()); +template < typename InputIter , typename Allocator > +flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a); + +flat_map(std::initializer_list ilist); + +flat_map(std::initializer_list ilist, const Compare& c); + +template < typename Allocator > +flat_map(std::initializer_list ilist, const Allocator& a); + +template < typename Allocator > +flat_map(std::initializer_list ilist, const Compare& c, const Allocator& a); + +template < typename Allocator > +flat_map(flat_map&& other, const Allocator& a); + +template < typename Allocator > +flat_map(const flat_map& other, const Allocator& a); flat_map(flat_map&& other); flat_map(const flat_map& other); flat_map& operator=(flat_map&& other); flat_map& operator=(const flat_map& other); -flat_map& operator=(std::initializer_list ilist); -allocator_type get_allocator() const; +flat_map& operator=(std::initializer_list ilist); ``` ### Iterators @@ -444,65 +449,58 @@ value_compare value_comp() const; template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > void swap( - flat_map& l, - flat_map& r); + flat_map& l, + flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator==( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator!=( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator<( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator>( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator<=( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator>=( - const flat_map& l, - const flat_map& r); + const flat_map& l, + const flat_map& r); ``` ## Flat Multiset diff --git a/headers/flat_hpp/flat_map.hpp b/headers/flat_hpp/flat_map.hpp index f914b62..b531731 100644 --- a/headers/flat_hpp/flat_map.hpp +++ b/headers/flat_hpp/flat_map.hpp @@ -20,8 +20,7 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare = std::less - , typename Allocator = std::allocator> - , typename Container = std::vector, Allocator> > + , typename Container = std::vector> > class flat_map final { class uber_comparer_type : public Compare { public: @@ -39,6 +38,10 @@ namespace flat_hpp bool operator()(typename Container::const_reference l, const Key& r) const { return Compare::operator()(l.first, r); } + + bool operator()(typename Container::const_reference l, typename Container::const_reference r) const { + return Compare::operator()(l.first, r.first); + } }; public: using key_type = Key; @@ -49,7 +52,6 @@ namespace flat_hpp using difference_type = typename Container::difference_type; using key_compare = Compare; - using allocator_type = Allocator; using container_type = Container; using reference = typename Container::reference; @@ -67,78 +69,80 @@ namespace flat_hpp bool operator()(const value_type& l, const value_type& r) const { return compare_(l.first, r.first); } - private: + protected: friend class flat_map; - explicit value_compare(const key_compare& compare) - : compare_(compare) {} + explicit value_compare(key_compare compare) + : compare_(std::move(compare)) {} private: key_compare compare_; }; - - static_assert( - std::is_same::value, - "Allocator::value_type must be same type as value_type"); - - static_assert( - std::is_same::value, - "Container::value_type must be same type as value_type"); - - static_assert( - std::is_same::value, - "Container::allocator_type must be same type as allocator_type"); public: flat_map() {} - explicit flat_map( - const Allocator& a) + explicit flat_map(const Compare& c) + : compare_(c) {} + + template < typename Allocator > + explicit flat_map(const Allocator& a) : data_(a) {} - explicit flat_map( - const Compare& c, - const Allocator& a = Allocator()) + template < typename Allocator > + flat_map(const Compare& c, const Allocator& a) : data_(a) , compare_(c) {} template < typename InputIter > - flat_map( - InputIter first, - InputIter last, - const Allocator& a) - : data_(a) { + flat_map(InputIter first, InputIter last) { insert(first, last); } template < typename InputIter > - flat_map( - InputIter first, - InputIter last, - const Compare& c = Compare(), - const Allocator& a = Allocator()) + flat_map(InputIter first, InputIter last, const Compare& c) + : compare_(c) { + insert(first, last); + } + + template < typename InputIter, typename Allocator > + flat_map(InputIter first, InputIter last, const Allocator& a) + : data_(a) { + insert(first, last); + } + + template < typename InputIter , typename Allocator > + flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a) : data_(a) , compare_(c) { insert(first, last); } - flat_map( - std::initializer_list ilist, - const Allocator& a) + flat_map(std::initializer_list ilist) { + insert(ilist); + } + + flat_map(std::initializer_list ilist, const Compare& c) + : compare_(c) { + insert(ilist); + } + + template < typename Allocator > + flat_map(std::initializer_list ilist, const Allocator& a) : data_(a) { insert(ilist); } - flat_map( - std::initializer_list ilist, - const Compare& c = Compare(), - const Allocator& a = Allocator()) + template < typename Allocator > + flat_map(std::initializer_list ilist, const Compare& c, const Allocator& a) : data_(a) , compare_(c) { insert(ilist); } + template < typename Allocator > flat_map(flat_map&& other, const Allocator& a) : data_(std::move(other.data_), a) , compare_(std::move(other.compare_)) {} + template < typename Allocator > flat_map(const flat_map& other, const Allocator& a) : data_(other.data_, a) , compare_(other.compare_) {} @@ -154,10 +158,6 @@ namespace flat_hpp return *this; } - allocator_type get_allocator() const { - return data_.get_allocator(); - } - iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } const_iterator cbegin() const noexcept { return data_.cbegin(); } @@ -230,28 +230,28 @@ namespace flat_hpp std::pair insert(value_type&& value) { const iterator iter = lower_bound(value.first); - return iter == end() || compare_(value.first, iter->first) + return iter == end() || compare_(value, *iter) ? std::make_pair(data_.insert(iter, std::move(value)), true) : std::make_pair(iter, false); } std::pair insert(const value_type& value) { const iterator iter = lower_bound(value.first); - return iter == end() || compare_(value.first, iter->first) + return iter == end() || compare_(value, *iter) ? std::make_pair(data_.insert(iter, value), true) : std::make_pair(iter, false); } iterator insert(const_iterator hint, value_type&& value) { - return (hint == begin() || compare_((hint - 1)->first, value.first)) - && (hint == end() || compare_(value.first, hint->first)) + return (hint == begin() || compare_(*(hint - 1), value)) + && (hint == end() || compare_(value, *hint)) ? data_.insert(hint, std::move(value)) : insert(std::move(value)).first; } iterator insert(const_iterator hint, const value_type& value) { - return (hint == begin() || compare_((hint - 1)->first, value.first)) - && (hint == end() || compare_(value.first, hint->first)) + return (hint == begin() || compare_(*(hint - 1), value)) + && (hint == end() || compare_(value, *hint)) ? data_.insert(hint, value) : insert(value).first; } @@ -303,7 +303,7 @@ namespace flat_hpp } size_type count(const key_type& key) const { - const auto iter = find(key); + const const_iterator iter = find(key); return iter != end() ? 1 : 0; } @@ -363,11 +363,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > void swap( - flat_map& l, - flat_map& r) + flat_map& l, + flat_map& r) { l.swap(r); } @@ -375,11 +374,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator==( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); @@ -388,11 +386,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator!=( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return !(l == r); } @@ -400,11 +397,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator<( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } @@ -412,11 +408,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator>( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return r < l; } @@ -424,11 +419,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator<=( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return !(r < l); } @@ -436,11 +430,10 @@ namespace flat_hpp template < typename Key , typename Value , typename Compare - , typename Allocator , typename Container > bool operator>=( - const flat_map& l, - const flat_map& r) + const flat_map& l, + const flat_map& r) { return !(l < r); } diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index 95ab531..c8fd349 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -19,8 +19,7 @@ namespace flat_hpp { template < typename Key , typename Compare = std::less - , typename Allocator = std::allocator - , typename Container = std::vector > + , typename Container = std::vector > class flat_set final { public: using key_type = Key; @@ -31,7 +30,6 @@ namespace flat_hpp using key_compare = Compare; using value_compare = Compare; - using allocator_type = Allocator; using container_type = Container; using reference = typename Container::reference; @@ -43,71 +41,73 @@ namespace flat_hpp using const_iterator = typename Container::const_iterator; using reverse_iterator = typename Container::reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; - - static_assert( - std::is_same::value, - "Allocator::value_type must be same type as value_type"); - - static_assert( - std::is_same::value, - "Container::value_type must be same type as value_type"); - - static_assert( - std::is_same::value, - "Container::allocator_type must be same type as allocator_type"); public: flat_set() {} - explicit flat_set( - const Allocator& a) + explicit flat_set(const Compare& c) + : compare_(c) {} + + template < typename Allocator > + explicit flat_set(const Allocator& a) : data_(a) {} - explicit flat_set( - const Compare& c, - const Allocator& a = Allocator()) + template < typename Allocator > + flat_set(const Compare& c, const Allocator& a) : data_(a) , compare_(c) {} template < typename InputIter > - flat_set( - InputIter first, - InputIter last, - const Allocator& a) - : data_(a) { + flat_set(InputIter first, InputIter last) { insert(first, last); } template < typename InputIter > - flat_set( - InputIter first, - InputIter last, - const Compare& c = Compare(), - const Allocator& a = Allocator()) + flat_set(InputIter first, InputIter last, const Compare& c) + : compare_(c) { + insert(first, last); + } + + template < typename InputIter, typename Allocator > + flat_set(InputIter first, InputIter last, const Allocator& a) + : data_(a) { + insert(first, last); + } + + template < typename InputIter, typename Allocator > + flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a) : data_(a) , compare_(c) { insert(first, last); } - flat_set( - std::initializer_list ilist, - const Allocator& a) + flat_set(std::initializer_list ilist) { + insert(ilist); + } + + flat_set(std::initializer_list ilist, const Compare& c) + : compare_(c) { + insert(ilist); + } + + template < typename Allocator > + flat_set(std::initializer_list ilist, const Allocator& a) : data_(a) { insert(ilist); } - flat_set( - std::initializer_list ilist, - const Compare& c = Compare(), - const Allocator& a = Allocator()) + template < typename Allocator > + flat_set(std::initializer_list ilist, const Compare& c, const Allocator& a) : data_(a) , compare_(c) { insert(ilist); } + template < typename Allocator > flat_set(flat_set&& other, const Allocator& a) : data_(std::move(other.data_), a) , compare_(std::move(other.compare_)) {} + template < typename Allocator > flat_set(const flat_set& other, const Allocator& a) : data_(other.data_, a) , compare_(other.compare_) {} @@ -123,10 +123,6 @@ namespace flat_hpp return *this; } - allocator_type get_allocator() const { - return data_.get_allocator(); - } - iterator begin() noexcept { return data_.begin(); } const_iterator begin() const noexcept { return data_.begin(); } const_iterator cbegin() const noexcept { return data_.cbegin(); } @@ -301,22 +297,20 @@ namespace flat_hpp { template < typename Key , typename Compare - , typename Allocator , typename Container > void swap( - flat_set& l, - flat_set& r) + flat_set& l, + flat_set& r) { l.swap(r); } template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator==( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin()); @@ -324,55 +318,50 @@ namespace flat_hpp template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator!=( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return !(l == r); } template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator<( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); } template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator>( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return r < l; } template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator<=( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return !(r < l); } template < typename Key , typename Compare - , typename Allocator , typename Container > bool operator>=( - const flat_set& l, - const flat_set& r) + const flat_set& l, + const flat_set& r) { return !(l < r); } diff --git a/untests/flat_map_tests.cpp b/untests/flat_map_tests.cpp index 2d6b976..eacca10 100644 --- a/untests/flat_map_tests.cpp +++ b/untests/flat_map_tests.cpp @@ -119,16 +119,16 @@ TEST_CASE("flat_map") { int, unsigned, std::less, - alloc_t>; + std::vector, alloc_t>>; using map2_t = flat_map< int, unsigned, std::greater, - alloc_t>; + std::vector, alloc_t>>; using vec_t = std::vector< - std::pair>; + std::pair, alloc_t>; { auto s0 = map_t(); @@ -162,13 +162,6 @@ TEST_CASE("flat_map") { REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({{0,1},{1,2}})); } - { - auto s0 = map_t(); - auto s1 = map_t(alloc_t(42)); - REQUIRE(s0.get_allocator().i == 0); - REQUIRE(s1.get_allocator().i == 42); - } - { auto s0 = map_t{{0,1}, {1,2}}; auto s1 = s0; @@ -179,8 +172,6 @@ TEST_CASE("flat_map") { REQUIRE(s2 == map_t{{0,1}, {1,2}}); auto s3 = map_t(s2, alloc_t(42)); REQUIRE(s2 == s3); - REQUIRE(s2.get_allocator().i == 0); - REQUIRE(s3.get_allocator().i == 42); auto s4 = map_t(std::move(s3), alloc_t(21)); REQUIRE(s3.empty()); REQUIRE(s4 == map_t{{0,1}, {1,2}}); @@ -251,7 +242,6 @@ TEST_CASE("flat_map") { int, unsigned, std::less, - alloc2_t, std::deque, alloc2_t>>; map2_t s1; diff --git a/untests/flat_set_tests.cpp b/untests/flat_set_tests.cpp index ea6b6af..ad7c508 100644 --- a/untests/flat_set_tests.cpp +++ b/untests/flat_set_tests.cpp @@ -110,8 +110,8 @@ TEST_CASE("flat_set") { } SECTION("ctors") { using alloc_t = dummy_allocator; - using set_t = flat_set, alloc_t>; - using set2_t = flat_set, alloc_t>; + using set_t = flat_set, std::vector>; + using set2_t = flat_set, std::vector>; using vec_t = std::vector; { @@ -146,13 +146,6 @@ TEST_CASE("flat_set") { REQUIRE(vec_t(s3.begin(), s3.end()) == vec_t({2,1,0})); } - { - auto s0 = set_t(); - auto s1 = set_t(alloc_t(42)); - REQUIRE(s0.get_allocator().i == 0); - REQUIRE(s1.get_allocator().i == 42); - } - { auto s0 = set_t{0,1,2}; auto s1 = s0; @@ -163,8 +156,6 @@ TEST_CASE("flat_set") { REQUIRE(s2 == set_t{0,1,2}); auto s3 = set_t(s2, alloc_t(42)); REQUIRE(s2 == s3); - REQUIRE(s2.get_allocator().i == 0); - REQUIRE(s3.get_allocator().i == 42); auto s4 = set_t(std::move(s3), alloc_t(21)); REQUIRE(s3.empty()); REQUIRE(s4 == set_t{0,1,2}); @@ -233,7 +224,6 @@ TEST_CASE("flat_set") { using set2_t = flat_set< int, std::less, - alloc2_t, std::deque>; set2_t s1; From 9f028a6ad4ee8047b0aeead6fa444cdc6499af62 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 08:52:11 +0700 Subject: [PATCH 08/11] set::iterator is std::const_iterator now --- headers/flat_hpp/flat_set.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/headers/flat_hpp/flat_set.hpp b/headers/flat_hpp/flat_set.hpp index c8fd349..6437dc1 100644 --- a/headers/flat_hpp/flat_set.hpp +++ b/headers/flat_hpp/flat_set.hpp @@ -37,9 +37,9 @@ namespace flat_hpp using pointer = typename Container::pointer; using const_pointer = typename Container::const_pointer; - using iterator = typename Container::iterator; + using iterator = typename Container::const_iterator; using const_iterator = typename Container::const_iterator; - using reverse_iterator = typename Container::reverse_iterator; + using reverse_iterator = typename Container::const_reverse_iterator; using const_reverse_iterator = typename Container::const_reverse_iterator; public: flat_set() {} From 12ec532aa1a9a01a8841f344562d718dc0079612 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 11:02:22 +0700 Subject: [PATCH 09/11] add simple lookup bench --- scripts/bench_map_lookup.sh | 8 ++++ scripts/bench_set_lookup.sh | 8 ++++ unbench/bench_base.hpp | 12 +++++ unbench/map_lookup_bench.cpp | 90 ++++++++++++++++++++++++++++++++++++ unbench/set_lookup_bench.cpp | 90 ++++++++++++++++++++++++++++++++++++ 5 files changed, 208 insertions(+) create mode 100755 scripts/bench_map_lookup.sh create mode 100755 scripts/bench_set_lookup.sh create mode 100644 unbench/map_lookup_bench.cpp create mode 100644 unbench/set_lookup_bench.cpp diff --git a/scripts/bench_map_lookup.sh b/scripts/bench_map_lookup.sh new file mode 100755 index 0000000..30d5120 --- /dev/null +++ b/scripts/bench_map_lookup.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_map_lookup --benchmark_format=csv > benchmark_map_lookup.csv +../scripts/bench_drawer.py -f benchmark_map_lookup.csv diff --git a/scripts/bench_set_lookup.sh b/scripts/bench_set_lookup.sh new file mode 100755 index 0000000..f96e5cd --- /dev/null +++ b/scripts/bench_set_lookup.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_set_lookup --benchmark_format=csv > benchmark_set_lookup.csv +../scripts/bench_drawer.py -f benchmark_set_lookup.csv diff --git a/unbench/bench_base.hpp b/unbench/bench_base.hpp index cf53719..fdf2af5 100644 --- a/unbench/bench_base.hpp +++ b/unbench/bench_base.hpp @@ -94,6 +94,18 @@ namespace flat_hpp_unbench v = std::move(nv); } + inline void generate_random_vector(std::size_t n, std::vector>& v) { + std::mt19937 engine(n); + std::uniform_int_distribution dist; + + std::vector> nv(n); + for ( std::size_t i = 0; i < n; ++i ) { + nv[i] = std::make_pair(dist(engine), dist(engine)); + } + + v = std::move(nv); + } + inline double min_bench_statistics(const std::vector& v) { return v.empty() ? 0.0 diff --git a/unbench/map_lookup_bench.cpp b/unbench/map_lookup_bench.cpp new file mode 100644 index 0000000..04d43d8 --- /dev/null +++ b/unbench/map_lookup_bench.cpp @@ -0,0 +1,90 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#ifdef BOOST_CONTAINER_FOUND +# include +#endif + +namespace +{ + template < typename Value > + void flat_map_lookup(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + flat_map s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e.first)); + benchmark::DoNotOptimize(s.find(e.second)); + } + } + } + +#ifdef BOOST_CONTAINER_FOUND + template < typename Value > + void boost_flat_map_lookup(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + boost::container::flat_map s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e.first)); + benchmark::DoNotOptimize(s.find(e.second)); + } + } + } +#endif + + template < typename Value > + void std_map_lookup(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + std::map s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e.first)); + benchmark::DoNotOptimize(s.find(e.second)); + } + } + } + + template < typename Value > + void std_unordered_map_lookup(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + std::unordered_map s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e.first)); + benchmark::DoNotOptimize(s.find(e.second)); + } + } + } +} + +BENCHMARK_TEMPLATE(flat_map_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_map_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif + +BENCHMARK_TEMPLATE(std_map_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_map_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); diff --git a/unbench/set_lookup_bench.cpp b/unbench/set_lookup_bench.cpp new file mode 100644 index 0000000..11810a7 --- /dev/null +++ b/unbench/set_lookup_bench.cpp @@ -0,0 +1,90 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#ifdef BOOST_CONTAINER_FOUND +# include +#endif + +namespace +{ + template < typename Value > + void flat_set_lookup(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + flat_set s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e)); + benchmark::DoNotOptimize(s.find(e * 2)); + } + } + } + +#ifdef BOOST_CONTAINER_FOUND + template < typename Value > + void boost_flat_set_lookup(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + boost::container::flat_set s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e)); + benchmark::DoNotOptimize(s.find(e * 2)); + } + } + } +#endif + + template < typename Value > + void std_set_lookup(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + std::set s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e)); + benchmark::DoNotOptimize(s.find(e * 2)); + } + } + } + + template < typename Value > + void std_unordered_set_lookup(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + std::unordered_set s(v.begin(), v.end()); + for ( auto _ : state ) { + for ( auto e : v ) { + benchmark::DoNotOptimize(s.find(e)); + benchmark::DoNotOptimize(s.find(e * 2)); + } + } + } +} + +BENCHMARK_TEMPLATE(flat_set_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_set_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif + +BENCHMARK_TEMPLATE(std_set_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_set_lookup, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); From 7e60c356e889107f44bc9812e3ff686af0752ab3 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 11:17:25 +0700 Subject: [PATCH 10/11] add simple foreach bench --- scripts/bench_map_foreach.sh | 8 +++ scripts/bench_set_foreach.sh | 8 +++ unbench/map_foreach_bench.cpp | 94 +++++++++++++++++++++++++++++++++++ unbench/set_foreach_bench.cpp | 94 +++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100755 scripts/bench_map_foreach.sh create mode 100755 scripts/bench_set_foreach.sh create mode 100644 unbench/map_foreach_bench.cpp create mode 100644 unbench/set_foreach_bench.cpp diff --git a/scripts/bench_map_foreach.sh b/scripts/bench_map_foreach.sh new file mode 100755 index 0000000..6b2860b --- /dev/null +++ b/scripts/bench_map_foreach.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_map_foreach --benchmark_format=csv > benchmark_map_foreach.csv +../scripts/bench_drawer.py -f benchmark_map_foreach.csv diff --git a/scripts/bench_set_foreach.sh b/scripts/bench_set_foreach.sh new file mode 100755 index 0000000..dc6e906 --- /dev/null +++ b/scripts/bench_set_foreach.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e + +BUILD_DIR=`dirname "$BASH_SOURCE"`/../build +cd $BUILD_DIR + +./unbench/flat.hpp.unbench --benchmark_filter=_set_foreach --benchmark_format=csv > benchmark_set_foreach.csv +../scripts/bench_drawer.py -f benchmark_set_foreach.csv diff --git a/unbench/map_foreach_bench.cpp b/unbench/map_foreach_bench.cpp new file mode 100644 index 0000000..db680b1 --- /dev/null +++ b/unbench/map_foreach_bench.cpp @@ -0,0 +1,94 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#ifdef BOOST_CONTAINER_FOUND +# include +#endif + +namespace +{ + template < typename Value > + void flat_map_foreach(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + flat_map s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.second.x; + } + benchmark::DoNotOptimize(acc); + } + } + +#ifdef BOOST_CONTAINER_FOUND + template < typename Value > + void boost_flat_map_foreach(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + boost::container::flat_map s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.second.x; + } + benchmark::DoNotOptimize(acc); + } + } +#endif + + template < typename Value > + void std_map_foreach(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + std::map s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.second.x; + } + benchmark::DoNotOptimize(acc); + } + } + + template < typename Value > + void std_unordered_map_foreach(benchmark::State& state) { + std::vector> v; + generate_random_vector(state.range(), v); + std::unordered_map s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.second.x; + } + benchmark::DoNotOptimize(acc); + } + } +} + +BENCHMARK_TEMPLATE(flat_map_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_map_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif + +BENCHMARK_TEMPLATE(std_map_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_map_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); diff --git a/unbench/set_foreach_bench.cpp b/unbench/set_foreach_bench.cpp new file mode 100644 index 0000000..18ccbdf --- /dev/null +++ b/unbench/set_foreach_bench.cpp @@ -0,0 +1,94 @@ +/******************************************************************************* + * This file is part of the "https://github.com/blackmatov/flat.hpp" + * For conditions of distribution and use, see copyright notice in LICENSE.md + * Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com) + ******************************************************************************/ + +#include "bench_base.hpp" +using namespace flat_hpp_unbench; + +#include +using namespace flat_hpp; + +#ifdef BOOST_CONTAINER_FOUND +# include +#endif + +namespace +{ + template < typename Value > + void flat_set_foreach(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + flat_set s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.x; + } + benchmark::DoNotOptimize(acc); + } + } + +#ifdef BOOST_CONTAINER_FOUND + template < typename Value > + void boost_flat_set_foreach(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + boost::container::flat_set s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.x; + } + benchmark::DoNotOptimize(acc); + } + } +#endif + + template < typename Value > + void std_set_foreach(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + std::set s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.x; + } + benchmark::DoNotOptimize(acc); + } + } + + template < typename Value > + void std_unordered_set_foreach(benchmark::State& state) { + std::vector v; + generate_random_vector(state.range(), v); + std::unordered_set s(v.begin(), v.end()); + for ( auto _ : state ) { + int acc = 0; + for ( const auto& e : s ) { + acc += e.x; + } + benchmark::DoNotOptimize(acc); + } + } +} + +BENCHMARK_TEMPLATE(flat_set_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +#ifdef BOOST_CONTAINER_FOUND + BENCHMARK_TEMPLATE(boost_flat_set_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); +#endif + +BENCHMARK_TEMPLATE(std_set_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); + +BENCHMARK_TEMPLATE(std_unordered_set_foreach, vec4) + ->ComputeStatistics("min", min_bench_statistics) + ->DenseRange(1,401,50); From 8cfec62b26390291a90c9a23a8981680a21919fd Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Thu, 9 May 2019 12:36:53 +0700 Subject: [PATCH 11/11] update README API --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f66e97..5a97393 100644 --- a/README.md +++ b/README.md @@ -75,9 +75,9 @@ class flat_set; | `const_reference` | `Container::const_reference` | | `pointer` | `Container::pointer` | | `const_pointer` | `Container::const_pointer` | -| `iterator` | `Container::iterator` | +| `iterator` | `Container::const_iterator` | | `const_iterator` | `Container::const_iterator` | -| `reverse_iterator` | `Container::reverse_iterator` | +| `reverse_iterator` | `Container::const_reverse_iterator` | | `const_reverse_iterator` | `Container::const_reverse_iterator` | ### Member functions