├── LICENSE ├── README.md ├── bench ├── Makefile ├── atomic.cpp ├── atomic.hpp ├── bench.cpp ├── chunkedseq.md ├── chunkedseq.ml ├── container.hpp ├── do_fifo.cpp ├── microtime.cpp └── microtime.hpp ├── doc ├── Makefile ├── chunkedseq.css ├── chunkedseq.md ├── extract_snippets.sh └── includes.hs ├── examples ├── Makefile ├── chunkedseq_1.cpp ├── chunkedseq_2.cpp ├── chunkedseq_3.cpp ├── chunkedseq_4.cpp ├── chunkedseq_5.cpp ├── chunkedseq_6.cpp ├── chunkedseq_7.cpp ├── iterator_1.cpp ├── map.hpp ├── map_1.cpp ├── map_2.cpp ├── segment_1.cpp ├── trivbootchunkedseq.hpp └── weighted_split.cpp ├── include ├── algebra.hpp ├── annotation.hpp ├── bootchunkedseq.hpp ├── cachedmeasure.hpp ├── chunk.hpp ├── chunkedbag.hpp ├── chunkedseq.hpp ├── chunkedseqbase.hpp ├── chunkedseqextras.hpp ├── fixedcapacity.hpp ├── fixedcapacitybase.hpp ├── ftree.hpp ├── itemsearch.hpp ├── iterator.hpp ├── measure.hpp └── segment.hpp └── script ├── benchmark.nix ├── default-sources.nix ├── default.nix ├── latest-sources.nix └── local-sources.nix /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Umut A. Acar, Arthur Chargueraud, and Mike Rainey 4 | 5 | ==== 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | 26 | ==== -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Quick-start guide 2 | ================= 3 | 4 | This package consists of a template library. As such, all files that 5 | you need to add to your code base are C++ header files. 6 | 7 | The code makes extensive use of C++11 features, such as lambda 8 | expressions. We have successfully tested the code base on GCC 4.9, but 9 | expect that is also compatible with recent Clang. 10 | 11 | What follows is a short guide to show you how to build one of the 12 | example programs. First, clone this repository. 13 | 14 | $ git clone https://github.com/deepsea-inria/chunkedseq.git 15 | 16 | Now, go to the folder that contains the example programs. 17 | 18 | $ cd chunkedseq/examples 19 | 20 | Then, build an example program. 21 | 22 | $ make chunkedseq_1.exe 23 | g++ -std=c++11 -I ../include chunkedseq_1.cpp -o chunkedseq_1.exe 24 | 25 | Finally, run the example program. 26 | 27 | $ ./chunkedseq_1.exe 28 | sum = 1000000000000 29 | 30 | Full documentation 31 | ================== 32 | 33 | See 34 | [http://deepsea.inria.fr/chunkedseq/](http://deepsea.inria.fr/chunkedseq/). 35 | -------------------------------------------------------------------------------- /bench/Makefile: -------------------------------------------------------------------------------- 1 | 2 | PACKAGE_PATH=../../ 3 | 4 | PBENCH_PATH=$(PACKAGE_PATH)/pbench 5 | CMDLINE_PATH=$(PACKAGE_PATH)/cmdline/include 6 | CHUNKEDSEQ_PATH=$(PACKAGE_PATH)/chunkedseq/include 7 | 8 | #################################################################### 9 | # Makefile options 10 | 11 | # Create a file called "settings.sh" in this folder if you want to 12 | # configure particular options. See section below for options. 13 | 14 | -include settings.sh 15 | 16 | #################################### 17 | # Example settings.sh 18 | # 19 | # USE_HWLOC=1 20 | # USE_CILK=1 21 | # USE_32_BIT_WORD_SIZE=1 22 | # CUSTOM_MALLOC_PREFIX=-ltcmalloc 23 | # CILK_EXTRAS_PREFIX=-L ../../../../cilk-plus-rts/lib -I ../../../../cilk-plus-rts/include -ldl -DCILK_RUNTIME_WITH_STATS 24 | #################################### 25 | 26 | #################################################################### 27 | 28 | INCLUDE_FILES=$(wildcard *.hpp) $(wildcard $(CHUNKEDSEQ_PATH)/*.hpp) $(wildcard $(CMDLINE_PATH)/*.hpp) 29 | 30 | INCLUDE_DIRECTIVES=-I $(CHUNKEDSEQ_PATH) -I $(CMDLINE_PATH) 31 | 32 | include $(PBENCH_PATH)/Makefile_common 33 | 34 | WARNINGS_PREFIX=-Wno-subobject-linkage -Wno-overflow -Wno-format 35 | COMMON_PREFIX=-std=c++1y $(WARNINGS_PREFIX) -ldl -DSKIP_MAP 36 | DEBUG_PREFIX=$(COMMON_PREFIX) -g3 -Og 37 | O2_PREFIX=-O2 -march=native -DNDEBUG -lm $(COMMON_PREFIX) $(CUSTOM_MALLOC_PREFIX) 38 | BENCH_PREFIX=$(COMMON_OPT_PREFIX) $(O2_PREFIX) 39 | CPP_FILES=microtime.cpp atomic.cpp 40 | 41 | %.dbg: %.cpp $(INCLUDE_FILES) 42 | g++ $(DEBUG_PREFIX) $(INCLUDE_DIRECTIVES) $(CPP_FILES) -o $@ $< 43 | 44 | %.exe: %.cpp $(INCLUDE_FILES) 45 | g++ $(BENCH_PREFIX) $(INCLUDE_DIRECTIVES) $(CPP_FILES) -o $@ $< 46 | 47 | clean: pbench_clean 48 | rm -f *.dbg *.exe 49 | -------------------------------------------------------------------------------- /bench/atomic.cpp: -------------------------------------------------------------------------------- 1 | /* COPYRIGHT (c) 2014 Umut Acar, Arthur Chargueraud, and Michael 2 | * Rainey 3 | * All rights reserved. 4 | * 5 | * \file atomic.cpp 6 | * \brief Atomic operations 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "atomic.hpp" 17 | 18 | /***********************************************************************/ 19 | 20 | namespace pasl { 21 | namespace util { 22 | namespace atomic { 23 | 24 | bool verbose; 25 | 26 | pthread_mutex_t print_lock; 27 | 28 | void init_print_lock() { 29 | pthread_mutex_init(&print_lock, nullptr); 30 | } 31 | 32 | void acquire_print_lock() { 33 | pthread_mutex_lock (&print_lock); 34 | } 35 | 36 | void release_print_lock() { 37 | pthread_mutex_unlock (&print_lock); 38 | } 39 | 40 | void die (const char *fmt, ...) { 41 | va_list ap; 42 | va_start (ap, fmt); 43 | acquire_print_lock(); { 44 | fprintf (stderr, "Fatal error -- "); 45 | vfprintf (stderr, fmt, ap); 46 | fprintf (stderr, "\n"); 47 | fflush (stderr); 48 | } 49 | release_print_lock(); 50 | va_end(ap); 51 | assert(false); 52 | exit (-1); 53 | } 54 | 55 | void afprintf (FILE* stream, const char *fmt, ...) { 56 | va_list ap; 57 | va_start (ap, fmt); 58 | acquire_print_lock(); { 59 | vfprintf (stream, fmt, ap); 60 | fflush (stream); 61 | } 62 | release_print_lock(); 63 | va_end(ap); 64 | } 65 | 66 | void aprintf (const char *fmt, ...) { 67 | va_list ap; 68 | va_start (ap, fmt); 69 | acquire_print_lock(); { 70 | vfprintf (stdout, fmt, ap); 71 | fflush (stdout); 72 | } 73 | release_print_lock(); 74 | va_end(ap); 75 | } 76 | 77 | void bprintf (const char *fmt, ...) { 78 | #ifdef DEBUG 79 | if (! verbose) 80 | return; 81 | va_list ap; 82 | va_start (ap, fmt); 83 | acquire_print_lock(); { 84 | vfprintf (stdout, fmt, ap); 85 | fflush (stdout); 86 | } 87 | release_print_lock(); 88 | va_end(ap); 89 | #endif 90 | } 91 | 92 | void xprintf (const char *fmt, ...) { 93 | #ifdef DEBUG 94 | if (! verbose) 95 | return; 96 | va_list ap; 97 | va_start (ap, fmt); 98 | vfprintf (stdout, fmt, ap); 99 | fflush (stdout); 100 | #endif 101 | } 102 | 103 | } 104 | } 105 | } 106 | 107 | /***********************************************************************/ 108 | -------------------------------------------------------------------------------- /bench/atomic.hpp: -------------------------------------------------------------------------------- 1 | /* COPYRIGHT (c) 2014 Umut Acar, Arthur Chargueraud, and Michael 2 | * Rainey 3 | * All rights reserved. 4 | * 5 | * \file atomic.hpp 6 | * \brief Atomic operations 7 | * 8 | */ 9 | 10 | #ifndef _PASL_UTIL_ATOMIC_H_ 11 | #define _PASL_UTIL_ATOMIC_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | /***********************************************************************/ 21 | 22 | namespace pasl { 23 | namespace util { 24 | namespace atomic { 25 | 26 | extern bool verbose; 27 | 28 | void init_print_lock(); 29 | 30 | void acquire_print_lock(); 31 | 32 | void release_print_lock(); 33 | 34 | /*! \brief Applies a given function while holding the print lock 35 | * 36 | * Acquires print lock; applies `print_fct`; releases print lock. 37 | */ 38 | template 39 | void msg(const Print_fct& print_fct) { 40 | acquire_print_lock(); 41 | print_fct(); 42 | release_print_lock(); 43 | } 44 | 45 | /*! \brief Applies a given function while holding the print lock, then 46 | * terminates the program 47 | * 48 | * Acquires print lock; applies `print_fct`; releases print lock; 49 | * terminates the program by calling std::exit(-1); 50 | */ 51 | template 52 | void fatal(const Print_fct& print_fct) { 53 | msg(print_fct); 54 | assert(false); 55 | std::exit(-1); 56 | } 57 | 58 | 59 | static inline void compiler_barrier () { 60 | asm volatile("" ::: "memory"); 61 | } 62 | 63 | 64 | /*---------------------------------------------------------------------*/ 65 | //! \todo replace instances of functions below by instances of functions above 66 | 67 | /*! \brief Prints a message to stdout and terminates the program. */ 68 | void die(const char *fmt, ...); 69 | 70 | /*! \brief Atomic `fprintf` 71 | * 72 | * Calls to this routine are serialized by a mutex lock. 73 | */ 74 | void afprintf(FILE* stream, const char *fmt, ...); 75 | 76 | /*! \brief Atomic `printf` 77 | * 78 | * Calls to this routine are serialized by a mutex lock. 79 | */ 80 | void aprintf(const char *fmt, ...); 81 | 82 | /*! \brief Debug printf (requires lock) 83 | */ 84 | void bprintf(const char *fmt, ...); 85 | 86 | /*! \brief Debug printf (does not require lock) 87 | */ 88 | void xprintf(const char *fmt, ...); 89 | 90 | /*---------------------------------------------------------------------*/ 91 | 92 | 93 | 94 | } // end namespace 95 | } // end namespace 96 | } // end namespace 97 | 98 | /***********************************************************************/ 99 | 100 | #endif /*! _PASL_UTIL_ATOMIC_H_ */ 101 | -------------------------------------------------------------------------------- /bench/bench.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Benchmarking for chunked sequences 9 | * \file fftree.cpp 10 | * 11 | */ 12 | 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "cmdline.hpp" 21 | 22 | // "ls_bag.hpp" 23 | #include "container.hpp" 24 | #include "fixedcapacity.hpp" 25 | #include "chunkedseq.hpp" 26 | #include "chunkedbag.hpp" 27 | #include "microtime.hpp" 28 | 29 | #ifdef USE_MALLOC_COUNT 30 | #include "malloc_count.h" 31 | #endif 32 | 33 | using namespace pasl; 34 | using namespace pasl::util; 35 | namespace chunkedseq = pasl::data::chunkedseq; 36 | 37 | /***********************************************************************/ 38 | 39 | typedef size_t result_t; 40 | 41 | typedef std::function thunk_t; 42 | 43 | //! \todo see cmdline invalid argument 44 | void failwith(std::string s) { 45 | std::cout << s << std::endl; 46 | exit(1); 47 | } 48 | 49 | result_t res = 0; 50 | double exec_time; 51 | 52 | /*---------------------------------------------------------------------*/ 53 | 54 | /* 55 | * Pseudo-random generator defined by the congruence S' = 69070 * S 56 | * mod (2^32 - 5). Marsaglia (CACM July 1993) says on page 107 that 57 | * this is a ``good one''. There you go. 58 | * 59 | * The literature makes a big fuss about avoiding the division, but 60 | * for us it is not worth the hassle. 61 | */ 62 | static const unsigned RNGMOD = ((1ULL << 32) - 5); 63 | static const unsigned RNGMUL = 69070U; 64 | unsigned rand_seed; 65 | 66 | unsigned myrand() { 67 | unsigned state = rand_seed; 68 | state = (unsigned)((RNGMUL * (unsigned long long)state) % RNGMOD); 69 | rand_seed = state; 70 | return state; 71 | } 72 | 73 | void mysrand(unsigned seed) { 74 | seed %= RNGMOD; 75 | seed += (seed == 0); /* 0 does not belong to the multiplicative 76 | group. Use 1 instead */ 77 | rand_seed = seed; 78 | } 79 | 80 | /*---------------------------------------------------------------------*/ 81 | 82 | class bytes_1 { 83 | public: 84 | char data; 85 | bytes_1() { } 86 | bytes_1(char c) : data(c) { } 87 | bytes_1(size_t i) { 88 | data = (char) (i % 256); 89 | } 90 | size_t get() const { 91 | return (size_t) data; 92 | } 93 | char get_char() const { 94 | return data; 95 | } 96 | bool operator==(const bytes_1 other) { 97 | return data == other.data; 98 | } 99 | operator unsigned char() const { 100 | return data; 101 | } 102 | }; 103 | 104 | class bytes_8 { 105 | public: 106 | uint64_t data; 107 | bytes_8() { } 108 | bytes_8(char c) { 109 | data = (uint64_t)c; 110 | } 111 | bytes_8(size_t i) { 112 | data = i; 113 | } 114 | size_t get() const { 115 | return data; 116 | } 117 | char get_char() const { 118 | return (char) (data % 256); 119 | } 120 | bool operator==(const bytes_8 other) { 121 | return data == other.data; 122 | } 123 | }; 124 | 125 | class bytes_64 { 126 | public: 127 | int64_t data[8]; 128 | bytes_64() { } 129 | bytes_64(char c) { 130 | for (int k = 0; k < 8; k++) 131 | data[k] = (int64_t)c; 132 | } 133 | bytes_64(size_t i) { 134 | for (int k = 0; k < 8; k++) 135 | data[k] = i; 136 | } 137 | size_t get() const { 138 | return data[0]; 139 | } 140 | char get_char() const { 141 | return (char) (data[0] % 256); 142 | } 143 | bool operator==(const bytes_64 other) { 144 | return data == other.data; 145 | } 146 | }; 147 | 148 | /* reorders in a random fashion the items of the given container 149 | */ 150 | template 151 | void shuffle(Datastruct& d) { 152 | size_t sz = d.size(); 153 | for (size_t i = 0; i < sz; i++) 154 | std::swap(d[i], d[rand() % sz]); 155 | } 156 | 157 | /*---------------------------------------------------------------------*/ 158 | /* Scenarios */ 159 | 160 | 161 | template 162 | thunk_t scenario_test() { 163 | typedef typename Datastruct::value_type value_type; 164 | size_t nb_total = (size_t) deepsea::cmdline::parse_or_default_long("n", 100000000); 165 | size_t repeat = (size_t) deepsea::cmdline::parse_or_default_long("r", 1000); 166 | size_t block = nb_total / repeat; 167 | return [=] { 168 | printf("length %lld\n",(long long int)block); 169 | uint64_t start_time = microtime::now(); 170 | Datastruct d; 171 | Datastruct r; 172 | res = 0; 173 | for (size_t j = 0; j < repeat; j++) { 174 | for (size_t i = 0; i < block; i++) { 175 | d.push_back(value_type(i)); 176 | res += i; 177 | } 178 | for (size_t i = 0; i < block; i++) { 179 | res += d.pop_front().get(); 180 | d.push_back(value_type(i)); 181 | size_t v = d.pop_front().get(); 182 | r.push_back(value_type(v)); 183 | } 184 | } 185 | exec_time = microtime::seconds_since(start_time); 186 | }; 187 | } 188 | 189 | 190 | // #define FIFO_LIFO_ONLY_COUNT_POP 1 191 | 192 | /* Common code for various lifo versions */ 193 | //! \todo factorize fifo and lifo 194 | template 195 | thunk_t scenario_lifo_with_or_without_pop() { 196 | typedef typename Datastruct::value_type value_type; 197 | size_t nb_total = (size_t) deepsea::cmdline::parse_or_default_long("n", 100000000); 198 | size_t repeat = (size_t) deepsea::cmdline::parse_or_default_long("r", 1000); 199 | size_t block = nb_total / repeat; 200 | return [=] { 201 | printf("length %lld\n",(long long int)block); 202 | uint64_t start_time = microtime::now(); 203 | Datastruct d; 204 | res = 0; 205 | for (size_t j = 0; j < repeat; j++) { 206 | for (size_t i = 0; i < block; i++) { 207 | d.push_back(value_type(i)); 208 | res += i; 209 | } 210 | #ifdef FIFO_LIFO_ONLY_COUNT_POP 211 | start_time = microtime::now(); 212 | #endif 213 | if (!SkipPop) { 214 | for (size_t i = 0; i < block; i++) { 215 | res += d.pop_back().get(); 216 | } 217 | } 218 | } 219 | // if (SkipPop) 220 | // res += d.size(); 221 | exec_time = microtime::seconds_since(start_time); 222 | }; 223 | } 224 | 225 | template 226 | thunk_t scenario_lifo() { 227 | return scenario_lifo_with_or_without_pop(); 228 | } 229 | 230 | template 231 | thunk_t scenario_fill_back() { 232 | return scenario_lifo_with_or_without_pop(); 233 | } 234 | 235 | template 236 | thunk_t scenario_fifo() { 237 | typedef typename Datastruct::value_type value_type; 238 | size_t nb_total = (size_t) deepsea::cmdline::parse_or_default_long("n", 100000000); 239 | size_t repeat = (size_t) deepsea::cmdline::parse_or_default_long("r", 1000); 240 | size_t block = nb_total / repeat; 241 | return [=] { 242 | printf("length %lld\n",(long long int)block); 243 | uint64_t start_time = microtime::now(); 244 | Datastruct d; 245 | res = 0; 246 | for (size_t j = 0; j < repeat; j++) { 247 | for (size_t i = 0; i < block; i++) { 248 | d.push_back(value_type(i)); 249 | res += i; 250 | } 251 | #ifdef FIFO_LIFO_ONLY_COUNT_POP 252 | start_time = microtime::now(); 253 | #endif 254 | for (size_t i = 0; i < block; i++) { 255 | res += d.pop_front().get(); 256 | } 257 | } 258 | exec_time = microtime::seconds_since(start_time); 259 | }; 260 | } 261 | 262 | 263 | // p should be 2 or more 264 | template 265 | void _scenario_split_merge(Datastruct* ds, size_t n, size_t p, size_t r, size_t h) { 266 | typedef typename Datastruct::value_type value_type; 267 | typedef typename Datastruct::size_type size_type; 268 | 269 | size_t nb_total = n / p; 270 | printf("length %lld\n",(long long int)nb_total); 271 | 272 | srand(14); 273 | for (size_type i = 0; i < p; i++) { 274 | for (size_type j = 0; j < nb_total; j++) 275 | ds[i].push_back(value_type((char)1)); 276 | } 277 | uint64_t start_time = microtime::now(); 278 | for (size_type k = 0; k < r; k++) { 279 | size_type b1 = rand() % p; 280 | size_type b2 = rand() % (p-1); 281 | if (b2 >= b1) 282 | b2++; 283 | // b1 != b2 284 | ds[b1].concat(ds[b2]); 285 | // ds[b2].empty() == true 286 | size_type b3 = rand() % (p-1); 287 | if (b3 >= b2) 288 | b3++; 289 | // b3 != b2 290 | Datastruct& src = ds[b3]; 291 | if (src.size() > 1) { 292 | size_t posn = src.size() / 2; 293 | src.split(posn, ds[b2]); 294 | } 295 | if (should_push) 296 | for (size_t i = 0; i < h; i++) 297 | src.push_back(value_type(i)); 298 | if (should_pop) 299 | for (size_t i = 0; i < h; i++) 300 | res += (size_type)src.pop_front().get(); 301 | } 302 | exec_time = microtime::seconds_since(start_time); 303 | res = 0; 304 | for (int i = 0; i < p; i++) 305 | res += ds[i].size(); 306 | } 307 | 308 | template 309 | thunk_t scenario_split_merge() { 310 | typedef typename Datastruct::value_type value_type; 311 | typedef typename Datastruct::size_type size_type; 312 | size_t n = (size_t) deepsea::cmdline::parse_or_default_long("n", 100000000); 313 | size_t p = (size_t) deepsea::cmdline::parse_or_default_long("p", std::max(n/100, (size_type)2)); 314 | size_t r = (size_t) deepsea::cmdline::parse_or_default_long("r", 100000); 315 | size_t h = (size_t) deepsea::cmdline::parse_or_default_long("h", 0); 316 | bool should_push = deepsea::cmdline::parse_or_default_bool("should_push", true); 317 | bool should_pop = deepsea::cmdline::parse_or_default_bool("should_pop", false); 318 | 319 | return [=] { 320 | Datastruct* ds = new Datastruct[p]; 321 | if (should_push && should_pop) 322 | _scenario_split_merge(ds, n, p, r, h); 323 | else if (! should_push && should_pop) 324 | _scenario_split_merge(ds, n, p, r, h); 325 | else if (should_push && ! should_pop) 326 | _scenario_split_merge(ds, n, p, r, h); 327 | else 328 | _scenario_split_merge(ds, n, p, r, h); 329 | delete [] ds; 330 | }; 331 | } 332 | 333 | template 334 | void filter(Datastruct& dst, Datastruct& src, const Filter& filt, int cutoff) { 335 | typedef typename Datastruct::value_type value_type; 336 | if (src.size() <= cutoff) { 337 | while (! src.empty()) { 338 | value_type item = src.pop_back(); 339 | if (filt(item)) 340 | dst.push_back(item); 341 | } 342 | } else { 343 | Datastruct src2; 344 | Datastruct dst2; 345 | size_t mid = src.size() / 2; 346 | src.split(mid, src2); 347 | filter(dst, src, filt, cutoff); 348 | filter(dst2, src2, filt, cutoff); 349 | dst.concat(dst2); 350 | } 351 | } 352 | 353 | template 354 | thunk_t scenario_filter() { 355 | typedef typename Datastruct::size_type size_type; 356 | typedef typename Datastruct::value_type value_type; 357 | size_t cutoff = deepsea::cmdline::parse_or_default_long("cutoff", 8096); 358 | size_t n = deepsea::cmdline::parse_or_default_long("n", 100000000); 359 | size_t r = (size_t) deepsea::cmdline::parse_or_default_long("r", 1); 360 | size_t nb_total = n / r; 361 | printf("length %lld\n",(long long int)nb_total); 362 | const size_t m = 1<<30; 363 | return [=] { 364 | Datastruct src; 365 | Datastruct dst; 366 | for (size_t i = 0; i < nb_total; i++) 367 | src.push_back(value_type(i)); 368 | auto filt = [] (value_type v) { 369 | return (v.get() % m) != 0; 370 | }; 371 | uint64_t start_time = microtime::now(); 372 | for (size_t i = 0; i < r; i++) { 373 | filter(dst, src, filt, cutoff); 374 | dst.swap(src); 375 | } 376 | exec_time = microtime::seconds_since(start_time); 377 | res = src.size() + dst.size(); 378 | //assert(dst.size() == n - ((n+m-1)/m)); 379 | }; 380 | } 381 | 382 | #ifndef SKIP_MAP 383 | 384 | /* All of these dictionary benchmarks are taken from: 385 | * http://tommyds.sourceforge.net/doc/benchmark.html 386 | */ 387 | #define PAYLOAD 16 // Size of the object 388 | 389 | template 390 | thunk_t scenario_map() { 391 | using map_type = Map; 392 | using key_type = typename map_type::key_type; 393 | using obj_type = Obj; 394 | using mapped_type = typename map_type::mapped_type; 395 | 396 | size_t n = deepsea::cmdline::parse_or_default_long("n", 1000000); 397 | bool test_random = deepsea::cmdline::parse_or_default_bool("test_random", true); 398 | key_type* INSERT = new key_type[n]; 399 | key_type* SEARCH = new key_type[n]; 400 | obj_type* OBJ = new obj_type[n]; 401 | 402 | // Initialize the keys 403 | for(long i=0;ivalue = key; 421 | 422 | // Insert it 423 | bag[key] = element; 424 | } 425 | }; 426 | 427 | deepsea::cmdline::dispatcher c; 428 | c.add("insert", [=] { 429 | map_type bag; 430 | uint64_t start_time = microtime::now(); 431 | init(bag); 432 | exec_time = microtime::seconds_since(start_time); 433 | res = bag.size(); 434 | }); 435 | c.add("change", [=] { 436 | map_type bag; 437 | init(bag); 438 | uint64_t start_time = microtime::now(); 439 | 440 | for(size_t i=0;ivalue = key; 455 | bag[key] = element; 456 | } 457 | exec_time = microtime::seconds_since(start_time); 458 | res = bag.size(); 459 | }); 460 | c.add("hit", [=] { 461 | map_type bag; 462 | init(bag); 463 | uint64_t start_time = microtime::now(); 464 | for(size_t i=0;ivalue != key) 477 | abort(); 478 | } 479 | exec_time = microtime::seconds_since(start_time); 480 | res = bag.size(); 481 | }); 482 | c.add("miss", [=] { 483 | map_type bag; 484 | init(bag); 485 | uint64_t start_time = microtime::now(); 486 | for(size_t i=0;ivalue != key) 513 | abort(); */ 514 | } 515 | exec_time = microtime::seconds_since(start_time); 516 | res = bag.size(); 517 | }); 518 | 519 | return c.find_by_arg("map_benchmark"); 520 | } 521 | #endif 522 | 523 | /*---------------------------------------------------------------------*/ 524 | // dispatch tests 525 | 526 | template 527 | void dispatch_by_scenario() { 528 | deepsea::cmdline::dispatcher c; 529 | c.add("test", scenario_test()); 530 | c.add("fifo", scenario_fifo()); 531 | c.add("lifo", scenario_lifo()); 532 | c.add("fill_back", scenario_fill_back()); 533 | c.add("split_merge", scenario_split_merge()); 534 | c.add("filter", scenario_filter()); 535 | c.dispatch("scenario"); 536 | } 537 | 538 | /*---------------------------------------------------------------------*/ 539 | // dispatch sequences 540 | 541 | #include "cachedmeasure.hpp" 542 | #include "fixedcapacity.hpp" 543 | template < 544 | template < 545 | class Item, 546 | int Chunk_capacity=512, 547 | class Cache = pasl::data::cachedmeasure::trivial, 548 | template> class Chunk_struct = pasl::data::fixedcapacity::heap_allocated::ringbuffer_ptr, 549 | class Item_alloc=std::allocator > class SeqStruct, 550 | class Item, 551 | template> class Chunk_struct> 552 | void dispatch_for_chunkedseq() { 553 | using Cache = pasl::data::cachedmeasure::trivial; 554 | static constexpr int default_chunksize = 512; 555 | deepsea::cmdline::dispatcher c; 556 | c.add("512", [] { dispatch_by_scenario >(); }); 557 | #ifndef SKIP_CHUNKSIZE 558 | c.add("64", [] { dispatch_by_scenario >(); }); 559 | c.add("128", [] { dispatch_by_scenario >(); }); 560 | c.add("256", [] { dispatch_by_scenario >(); }); 561 | c.add("1024", [] { dispatch_by_scenario >(); }); 562 | c.add("2048", [] { dispatch_by_scenario >(); }); 563 | c.add("4096", [] { dispatch_by_scenario >(); }); 564 | c.add("8192", [] { dispatch_by_scenario >(); }); 565 | #endif 566 | c.dispatch_or_default("chunk_size", std::to_string(default_chunksize)); 567 | } 568 | 569 | 570 | template , 573 | template> class Chunk_struct=data::fixedcapacity::heap_allocated::ringbuffer_ptr, 574 | class Item_alloc=std::allocator > 575 | using mystack = chunkedseq::bootstrapped::stack; 576 | 577 | template , 580 | template> class Chunk_struct=data::fixedcapacity::heap_allocated::ringbuffer_ptr, 581 | class Item_alloc=std::allocator > 582 | using mybag = chunkedseq::bootstrapped::bagopt; 583 | 584 | 585 | template , 588 | template> class Chunk_struct=data::fixedcapacity::heap_allocated::ringbuffer_ptr, 589 | class Item_alloc=std::allocator > 590 | using myfftreestack = chunkedseq::ftree::stack; 591 | 592 | template , 595 | template> class Chunk_struct=data::fixedcapacity::heap_allocated::ringbuffer_ptr, 596 | class Item_alloc=std::allocator > 597 | using myfftreebag = chunkedseq::ftree::bagopt; 598 | 599 | template 600 | void dispatch_by_sequence() { 601 | deepsea::cmdline::dispatcher c; 602 | #ifndef SKIP_DEQUE 603 | c.add("stl_deque", [] { 604 | using seq_type = pasl::data::stl::deque_seq; 605 | dispatch_by_scenario(); 606 | }); 607 | #endif 608 | #ifndef SKIP_ROPE 609 | #ifdef HAVE_ROPE 610 | c.add("stl_rope", [] { 611 | using seq_type = pasl::data::stl::rope_seq; 612 | dispatch_by_scenario(); 613 | }); 614 | #endif 615 | #endif 616 | #ifndef SKIP_CHUNKEDSEQ 617 | c.add("chunkedseq", [] { 618 | dispatch_for_chunkedseq(); 619 | }); 620 | #endif 621 | #ifndef SKIP_CHUNKEDSEQ_OPT 622 | c.add("chunkedseq_stack", [] { 623 | dispatch_for_chunkedseq(); 624 | }); 625 | c.add("chunkedseq_bag", [] { 626 | dispatch_for_chunkedseq(); 627 | }); 628 | #endif 629 | 630 | #ifndef SKIP_FTREE 631 | c.add("chunkedftree", [] { 632 | dispatch_for_chunkedseq(); 633 | }); 634 | #endif 635 | #ifndef SKIP_FTREE_OPT 636 | c.add("chunkedftree_stack", [] { 637 | dispatch_for_chunkedseq(); 638 | }); 639 | c.add("chunkedftree_bag", [] { 640 | dispatch_for_chunkedseq(); 641 | }); 642 | #endif 643 | c.dispatch("sequence"); 644 | } 645 | 646 | /*---------------------------------------------------------------------*/ 647 | // dispatch itemsize 648 | 649 | void dispatch_by_itemsize() { 650 | static constexpr int default_itemsize = 8; 651 | deepsea::cmdline::dispatcher c; 652 | c.add("8", [] { dispatch_by_sequence(); }); 653 | #ifndef SKIP_ITEMSIZE 654 | c.add("1", [] { dispatch_by_sequence(); }); 655 | c.add("64", [] { dispatch_by_sequence(); }); 656 | #endif 657 | c.dispatch_or_default("itemsize", std::to_string(default_itemsize)); 658 | } 659 | 660 | /*---------------------------------------------------------------------*/ 661 | // dispatch maps 662 | 663 | #ifndef SKIP_MAP 664 | void dispatch_by_map() { 665 | deepsea::cmdline::dispatcher c; 666 | using key_type = long; 667 | using obj_type = struct { 668 | key_type value; 669 | char payload[PAYLOAD]; 670 | }; 671 | using value_type = obj_type*; 672 | using stl_map_type = std::map; 673 | using chunkedseq_map_type = data::map::map; 674 | using unordered_map_type = std::unordered_map; 675 | c.add("stl_map", scenario_map()); 676 | c.add("chunkedseq_map", scenario_map()); 677 | c.add("stl_unordered_set", scenario_map()); 678 | c.dispatch("map"); 679 | } 680 | #else 681 | void dispatch_by_map() { 682 | abort(); 683 | } 684 | #endif 685 | 686 | 687 | /*---------------------------------------------------------------------*/ 688 | 689 | void dispatch_by_benchmark_mode() { 690 | deepsea::cmdline::dispatcher c; 691 | c.add("sequence", [] { dispatch_by_itemsize(); }); 692 | c.add("map", [] { dispatch_by_map(); }); 693 | c.dispatch_or_default("mode", "sequence"); 694 | } 695 | 696 | int main(int argc, char** argv) { 697 | deepsea::cmdline::set(argc, argv); 698 | mysrand(233432432); 699 | res = 0; 700 | 701 | dispatch_by_benchmark_mode(); 702 | 703 | printf ("exectime %lf\n", exec_time); 704 | printf("result %lld\n", (long long int)res); 705 | 706 | #ifdef USE_MALLOC_COUNT 707 | malloc_pasl_report(); 708 | #endif 709 | return 0; 710 | } 711 | 712 | 713 | 714 | 715 | /***********************************************************************/ 716 | -------------------------------------------------------------------------------- /bench/chunkedseq.md: -------------------------------------------------------------------------------- 1 | % `chunkedseq` Benchmarking User's Guide 2 | % Umut Acar 3 | Arthur Charguéraud 4 | Mike Rainey 5 | % 5 August 2014 6 | 7 | Synopsis 8 | ======== 9 | 10 | chunkedseq.byte [*ACTION*] [*PARAMETERS*]... 11 | 12 | Description 13 | =========== 14 | 15 | chunkedseq.byte is a script whose purpose is to benchmark the implementation 16 | of our chunked-sequence data structure. The script automates all aspects of 17 | the benchmarking: building binaries, generation of input data, running 18 | of experiments, and output of experimental data, including plots, tables, 19 | and raw data. 20 | 21 | Options 22 | ======= 23 | 24 | Actions 25 | ------- 26 | 27 | The action selects the overall behavior of the script. 28 | *ACTION* can be one of the following: 29 | 30 | `configure` 31 | : Generate configuration files that are required by PASL. 32 | 33 | `generate` 34 | : Generate graph files that are to be used by the graph-traversal 35 | experiments. 36 | 37 | `fifo` 38 | : Run the "fifo" benchmark. 39 | 40 | `lifo` 41 | : Run the "lifo" benchmark. 42 | 43 | `split_merge` 44 | : Run the "split-merge" benchmark. 45 | 46 | `bfs` 47 | : Run the serial BFS benchmark. 48 | 49 | `dfs` 50 | : Run the serial DFS benchmark. 51 | 52 | `pbfs` 53 | : Run the parallel BFS benchmark. 54 | 55 | `filter` 56 | : Run the parallel filter benchmark. 57 | 58 | `map` 59 | : Run the dynamic-dictionary benchmark. 60 | 61 | `report` 62 | : Generate a table reporting on execution times of benchmarks runs. 63 | 64 | `all` 65 | : Build binaries, generate graphs, and then run all benchmarks. 66 | 67 | Parameters 68 | ---------- 69 | 70 | Parameters select finer details of the behavior of the script. 71 | *PARAMETERS* can be zero or more of the following: 72 | 73 | `-runs` *n* 74 | : Specifies the number of times *n* to execute for each combination of 75 | benchmark parameters. Default is 1. 76 | 77 | `-timeout` *n* 78 | : Force a specific timeout for runs. The timeout value *n* is measured 79 | in seconds. 80 | 81 | `-mode` *m* 82 | : Where *m* is `normal` (discard all previous results) or `append`. 83 | (append to previous results) or `replace` (discard results that are ran again) 84 | or `complete` (add results that are missing). 85 | 86 | `--virtual_run` 87 | : Only show the list of commands that would be called to run the benchmarks. 88 | 89 | `--virtual_generate` 90 | : Only show the list of commands that would be called to generate the graphs 91 | used by the graph-search experiments. 92 | 93 | `-skip` *a1*,*a2*,... 94 | : Skip selected actions. Note: `-skip run` automatically activates 95 | `-skip make`. 96 | 97 | `-only` *a1*,*a2*,... 98 | : Perform only selected actions. 99 | 100 | `-path_to_graph_data` *PATH* 101 | : Force a specific path in which to store graph data. Default is `_data`. 102 | 103 | `-path_to_pasl` *PATH* 104 | : Force a specific path to the root of the PASL source tree. Default is `.`. 105 | 106 | Compilation parameters 107 | ---------------------- 108 | 109 | `-allocator` *a* 110 | : Select a drop-in replacement for malloc/free by specifiying a custom 111 | library *a*. 112 | 113 | `--use_hwloc` 114 | : Compile PASL binaries with support for hwloc. 115 | 116 | `-path_to_`*PACKAGE* *PATH* 117 | : Configure PASL to look for package named *PACKAGE* in the 118 | path *PATH*. 119 | 120 | Sample applications 121 | =================== 122 | 123 | - Configure all PASL binaries to use hwloc. 124 | 125 | ./chunkedseq.byte configure --use_hwloc -path_to_hwloc /pathto/hwloc 126 | 127 | - Configure all PASL binaries to use tcmalloc. 128 | 129 | ./chunkedseq.byte configure -allocator tcmalloc -path_to_tcmalloc /pathto/tcmalloc 130 | 131 | - Run all experiments but do not plot. 132 | 133 | ./chunkedseq.byte -skip plot all 134 | 135 | - Run just graph experiments and neither plot nor build dependencies. 136 | 137 | ./chunkedseq.byte -skip plot,make dfs 138 | ./chunkedseq.byte -skip plot,make bfs 139 | ./chunkedseq.byte -skip plot,make pbfs 140 | 141 | - Generate a table reporting on the three experiments from above. 142 | 143 | ./chunkedseq.byte report 144 | 145 | See also 146 | ======== 147 | 148 | The chunkedseq source code and all documentation can be downloaded from 149 | 150 | -------------------------------------------------------------------------------- /bench/container.hpp: -------------------------------------------------------------------------------- 1 | /* COPYRIGHT (c) 2014 Umut Acar, Arthur Chargueraud, and Michael 2 | * Rainey 3 | * All rights reserved. 4 | * 5 | * \file container.hpp 6 | * \brief Several container data structures 7 | * 8 | */ 9 | 10 | #ifndef _PASL_DATA_CONTAINER_H_ 11 | #define _PASL_DATA_CONTAINER_H_ 12 | 13 | #include 14 | #include 15 | #ifdef HAVE_ROPE 16 | #include 17 | #include 18 | #endif 19 | #ifdef HAVE_CORD 20 | extern "C" 21 | { 22 | #include "gc.h" /* For GC_INIT() only */ /* nodepend */ 23 | #include 24 | } 25 | #endif 26 | 27 | #include "atomic.hpp" 28 | 29 | /***********************************************************************/ 30 | 31 | namespace pasl { 32 | namespace data { 33 | 34 | /*---------------------------------------------------------------------*/ 35 | /* Stylized malloc/free */ 36 | 37 | template 38 | Value* mynew() { 39 | Value* res = (Value*)malloc(sizeof(Value)); 40 | if (res == NULL) 41 | util::atomic::die("mynew returned NULL"); 42 | return res; 43 | } 44 | 45 | template 46 | Value* mynew_array(size_t nb) { 47 | Value* res = (Value*)malloc(size_t(sizeof(Value)) * nb); 48 | if (res == NULL) 49 | util::atomic::die("mynew_array returned NULL"); 50 | return res; 51 | } 52 | 53 | static inline void myfree(void* p) { 54 | free(p); 55 | } 56 | 57 | /*---------------------------------------------------------------------*/ 58 | /* Contiguous array interface; destructor does not deallocate 59 | * underlying array 60 | */ 61 | 62 | template 63 | class pointer_seq { 64 | public: 65 | 66 | typedef size_t size_type; 67 | typedef Item value_type; 68 | typedef pointer_seq self_type; 69 | 70 | value_type* array; 71 | size_type sz; 72 | 73 | pointer_seq() 74 | : array(NULL), sz(0) { } 75 | 76 | pointer_seq(value_type* array, size_type sz) 77 | : array(array), sz(sz) { } 78 | 79 | ~pointer_seq() { 80 | clear(); 81 | } 82 | 83 | void clear() { 84 | sz = 0; 85 | array = NULL; 86 | } 87 | 88 | value_type& operator[](size_type ix) const { 89 | assert(ix >= 0); 90 | assert(ix < sz); 91 | return array[ix]; 92 | } 93 | 94 | size_type size() const { 95 | return sz; 96 | } 97 | 98 | void swap(self_type& other) { 99 | std::swap(sz, other.sz); 100 | std::swap(array, other.array); 101 | } 102 | 103 | void alloc(size_type n) { 104 | util::atomic::die("operation not supported"); 105 | } 106 | 107 | void set_data(value_type* data) { 108 | this->data = data; 109 | } 110 | 111 | value_type* data() const { 112 | return array; 113 | } 114 | 115 | template 116 | void for_each(const Body& b) const { 117 | for (size_type i = 0; i < sz; i++) 118 | b(array[i]); 119 | } 120 | 121 | }; 122 | 123 | /*---------------------------------------------------------------------*/ 124 | /* Contiguous array; destructor deallocates underlying array */ 125 | 126 | template 127 | class array_seq { 128 | public: 129 | 130 | typedef array_seq self_type; 131 | typedef Item value_type; 132 | typedef size_t size_type; 133 | 134 | private: 135 | 136 | size_type sz; 137 | value_type* array; 138 | 139 | public: 140 | 141 | array_seq() 142 | : sz(0), array(NULL) { } 143 | 144 | ~array_seq() { 145 | clear(); 146 | } 147 | 148 | void clear() { 149 | if (array != NULL) 150 | myfree(array); 151 | array = NULL; 152 | } 153 | 154 | value_type& operator[](size_type ix) const { 155 | assert(ix >= 0); 156 | assert(ix < sz); 157 | return array[ix]; 158 | } 159 | 160 | size_type size() const { 161 | return sz; 162 | } 163 | 164 | void swap(self_type& other) { 165 | std::swap(sz, other.sz); 166 | std::swap(array, other.array); 167 | } 168 | 169 | void alloc(size_type n) { 170 | value_type* old_array = array; 171 | sz = n; 172 | array = mynew_array(sz); 173 | if (old_array != NULL) { 174 | // TODO: use memcpy to copy old to new array 175 | util::atomic::die("todo"); 176 | myfree(old_array); 177 | } 178 | } 179 | 180 | void set_data(value_type* data) { 181 | this->data = data; 182 | } 183 | 184 | value_type* data() const { 185 | return array; 186 | } 187 | 188 | }; 189 | 190 | namespace stl { 191 | 192 | /*---------------------------------------------------------------------*/ 193 | /* Wrapper for STL vector */ 194 | 195 | template 196 | class vector_seq { 197 | public: 198 | 199 | typedef vector_seq self_type; 200 | typedef Item value_type; 201 | typedef size_t size_type; 202 | typedef vector_seq alias_type; 203 | 204 | mutable std::vector vec; 205 | 206 | size_type size() const { 207 | return vec.size(); 208 | } 209 | 210 | bool empty() const { 211 | return vec.empty(); 212 | } 213 | 214 | 215 | Item& back() { 216 | return vec.back(); 217 | } 218 | 219 | Item& front() { 220 | util::atomic::die("unsupported operation"); 221 | return vec.back(); 222 | } 223 | 224 | Item pop_back() { 225 | Item x = vec.back(); 226 | vec.pop_back(); 227 | return x; 228 | } 229 | 230 | Item pop_front() { 231 | util::atomic::die("unsupported operation"); 232 | Item x = vec.back(); 233 | vec.pop_back(); 234 | return x; 235 | } 236 | 237 | void push_back(const Item& x) { 238 | vec.push_back(x); 239 | } 240 | 241 | void push_front(const Item& x) { 242 | util::atomic::die("unsupported operation"); 243 | } 244 | 245 | void pushn_back(value_type* vs, size_type nb) { 246 | size_t sz = size(); 247 | vec.resize(sz + nb); 248 | for (size_t i = 0; i < nb; i++) 249 | vec[i + sz] = vs[i]; 250 | } 251 | 252 | void pushn_back(const value_type v, size_type nb) { 253 | for (size_t i = 0; i < nb; i++) 254 | push_back(v); 255 | } 256 | 257 | void popn_back(value_type* vs, size_type nb) { 258 | size_t sz = size(); 259 | size_t st = sz - nb; 260 | for (size_t i = 0; i < nb; i++) 261 | vs[i] = vec[st + i]; 262 | vec.resize(sz - nb); 263 | } 264 | 265 | value_type& operator[](size_type ix) const { 266 | return vec[ix]; 267 | } 268 | 269 | value_type& operator[](int ix) const { 270 | return vec[ix]; 271 | } 272 | 273 | template 274 | void for_each(const Loop_body& body) { 275 | for (size_t i = 0; i < size(); i++) 276 | body(vec[i]); 277 | } 278 | 279 | typedef typename std::vector::iterator iterator; 280 | iterator begin() { 281 | return vec.begin(); 282 | } 283 | 284 | iterator end() { 285 | return vec.end(); 286 | } 287 | 288 | iterator insert(iterator pos, const Item& val) { 289 | return vec.insert(pos, val); 290 | } 291 | 292 | void transfer_to_back(self_type& dst) { 293 | int nb = (int)dst.size(); 294 | for (int i = 0; i < nb; i++) 295 | push_back(dst.vec[i]); 296 | dst.clear(); 297 | } 298 | 299 | void transfer_from_back_to_front_by_position(self_type& dst, iterator it) { 300 | for (auto it2 = it; it2 != end(); it2++) 301 | dst.push_back(*it2); 302 | vec.erase(it, end()); 303 | } 304 | 305 | void split_approximate(self_type& dst) { 306 | size_t mid = size() / 2; 307 | transfer_from_back_to_front_by_position(dst, begin() + mid); 308 | } 309 | 310 | value_type* data() const { 311 | return vec.data(); 312 | } 313 | 314 | void swap(self_type& other) { 315 | vec.swap(other.vec); 316 | } 317 | 318 | void alloc(size_type n) { 319 | vec.resize(n); 320 | } 321 | 322 | void clear() { 323 | vec.clear(); 324 | } 325 | 326 | }; 327 | 328 | /*---------------------------------------------------------------------*/ 329 | /* Wrapper for STL deque */ 330 | 331 | template 332 | class deque_seq { 333 | public: 334 | 335 | typedef deque_seq self_type; 336 | typedef Item value_type; 337 | typedef size_t size_type; 338 | 339 | mutable std::deque deque; 340 | 341 | size_type size() const { 342 | return deque.size(); 343 | } 344 | 345 | bool empty() const { 346 | return deque.empty(); 347 | } 348 | 349 | Item& back() { 350 | return deque.back(); 351 | } 352 | 353 | Item& front() { 354 | return deque.front(); 355 | } 356 | 357 | Item pop_back() { 358 | Item x = deque.back(); 359 | deque.pop_back(); 360 | return x; 361 | } 362 | 363 | Item pop_front() { 364 | Item x = deque.front(); 365 | deque.pop_front(); 366 | return x; 367 | } 368 | 369 | void push_back(const Item& x) { 370 | deque.push_back(x); 371 | } 372 | 373 | void push_front(const Item& x) { 374 | deque.push_front(x); 375 | } 376 | 377 | void backn(value_type* dst, size_type nb) const { 378 | size_t sz = size(); 379 | assert(nb <= sz); 380 | size_t off = sz - nb; 381 | for (size_t i = 0; i < nb; i++) 382 | dst[i] = deque[i+off]; 383 | } 384 | 385 | void frontn(value_type* dst, size_type nb) const { 386 | size_t sz = size(); 387 | assert(nb <= sz); 388 | for (size_t i = 0; i < nb; i++) 389 | dst[i] = deque[i]; 390 | } 391 | 392 | void pushn_back(const value_type v, size_type nb) { 393 | for (size_t i = 0; i < nb; i++) 394 | push_back(v); 395 | } 396 | 397 | void pushn_back(value_type* vs, size_type nb) { 398 | size_t sz = size(); 399 | deque.resize(sz + nb); 400 | for (size_t i = 0; i < nb; i++) 401 | deque[i + sz] = vs[i]; 402 | } 403 | 404 | void pushn_front(value_type* vs, size_type nb) { 405 | vs += nb; 406 | for (size_t i = 0; i < nb; i++) { 407 | vs--; 408 | push_front(*vs); 409 | } 410 | } 411 | 412 | void popn_back(value_type* vs, size_type nb) { 413 | size_t sz = size(); 414 | assert(nb <= sz); 415 | size_t st = sz - nb; 416 | for (size_t i = 0; i < nb; i++) 417 | vs[i] = deque[i + st]; 418 | deque.resize(sz - nb); 419 | } 420 | 421 | void popn_front(value_type* vs, size_type nb) { 422 | assert(nb <= size()); 423 | for (size_t i = 0; i < nb; i++) 424 | vs[i] = deque[i]; 425 | for (size_t i = 0; i < nb; i++) 426 | pop_front(); 427 | } 428 | 429 | void clear() { 430 | deque.clear(); 431 | } 432 | 433 | value_type& operator[](size_type ix) const { 434 | assert(ix >= 0); 435 | assert(ix < size()); 436 | return deque[ix]; 437 | } 438 | 439 | value_type& operator[](int ix) const { 440 | assert(ix >= 0); 441 | assert(ix < size()); 442 | return deque[ix]; 443 | } 444 | 445 | template 446 | void for_each(const Loop_body& body) const { 447 | for (auto it = deque.begin(); it != deque.end(); it++) 448 | body(*it); 449 | } 450 | 451 | typedef typename std::deque::iterator iterator; 452 | iterator begin() const { 453 | return deque.begin(); 454 | } 455 | 456 | iterator end() const { 457 | return deque.end(); 458 | } 459 | 460 | iterator insert(iterator pos, const Item& val) { 461 | return deque.insert(pos, val); 462 | } 463 | 464 | iterator erase(iterator first, iterator last) { 465 | return deque.erase(first, last); 466 | } 467 | 468 | void split(size_type n, self_type& dst) { 469 | auto it = begin() + n; 470 | for (auto it2 = it; it2 != end(); it2++) 471 | dst.push_back(*it2); 472 | deque.erase(it, end()); 473 | } 474 | 475 | void split_approximate(self_type& other) { 476 | split(size() / 2, other); 477 | } 478 | 479 | void concat(self_type& dst) { 480 | int nb = (int)dst.size(); 481 | for (int i = 0; i < nb; i++) 482 | push_back(dst.deque[i]); 483 | dst.clear(); 484 | } 485 | 486 | void swap(self_type& other) { 487 | deque.swap(other.deque); 488 | } 489 | 490 | void alloc(size_type n) { 491 | deque.resize(n); 492 | } 493 | 494 | value_type* data() const { 495 | util::atomic::die("not supported"); 496 | return NULL; 497 | } 498 | 499 | bool operator==(const self_type& other) const { 500 | return deque == other.deque; 501 | } 502 | 503 | }; 504 | 505 | /*---------------------------------------------------------------------*/ 506 | /* Wrapper for STL rope */ 507 | 508 | #ifdef HAVE_ROPE 509 | template 510 | class rope_seq { 511 | public: 512 | typedef __gnu_cxx::rope > container_t; 513 | typedef Item value_type; 514 | typedef typename container_t::size_type size_type; 515 | mutable container_t v; 516 | using self_type = rope_seq; 517 | 518 | rope_seq() {} 519 | 520 | rope_seq(size_t nb, value_type val) { 521 | v.append(nb, val); 522 | } 523 | 524 | size_t size() const { 525 | return v.size(); 526 | } 527 | 528 | bool empty() const { 529 | return v.empty(); 530 | } 531 | 532 | void push_back(Item i) { 533 | v.push_back(i); 534 | } 535 | 536 | Item pop_back() { 537 | Item i = v.back(); 538 | v.pop_back(); 539 | return i; 540 | } 541 | 542 | void push_front(Item i) { 543 | v.push_front(i); 544 | } 545 | 546 | Item pop_front() { 547 | Item i = v.front(); 548 | v.pop_front(); 549 | return i; 550 | } 551 | 552 | typedef typename container_t::iterator iterator; 553 | iterator begin() const { 554 | return v.mutable_begin(); 555 | } 556 | 557 | iterator end() const { 558 | return v.mutable_end(); 559 | } 560 | 561 | iterator insert(iterator pos, const Item& val) { 562 | return v.insert(pos, val); 563 | } 564 | 565 | void clear() { 566 | v.clear(); 567 | } 568 | 569 | void pushn_back(value_type* vs, size_t nb) { 570 | for (size_t i = 0; i < nb; i++) 571 | push_back(vs[i]); 572 | } 573 | 574 | void pushn_back(const value_type v, size_t nb) { 575 | for (size_t i = 0; i < nb; i++) 576 | push_back(v); 577 | } 578 | 579 | void popn_back(value_type* vs, size_t nb) { 580 | for (size_t i = 0; i < nb; i++) 581 | pop_back(); 582 | } 583 | 584 | value_type operator[](int ix) const { 585 | return v[ix]; 586 | } 587 | 588 | value_type operator[](size_t ix) const { 589 | return v[ix]; 590 | } 591 | 592 | template 593 | void for_each(const Loop_body& body) { 594 | for (size_t i = 0; i < size(); i++) 595 | body(i, v[i]); 596 | } 597 | 598 | void concat(rope_seq& r) { 599 | v.append(r.v); 600 | r.v.erase(r.v.mutable_begin(), r.v.mutable_end()); 601 | } 602 | 603 | void split(size_type n, self_type& dst) { 604 | auto it = begin() + n; 605 | auto r = v.substr(it, v.mutable_end()); 606 | v.erase(it, v.mutable_end()); 607 | dst.v.append(r); 608 | } 609 | 610 | void split_approximate(rope_seq& dst) { 611 | assert(size() >= 2); 612 | size_t mid = size() / 2; 613 | split(begin() + mid, dst); 614 | } 615 | 616 | void swap(rope_seq& other) { 617 | v.swap(other.v); 618 | } 619 | 620 | }; 621 | #endif 622 | 623 | } // end namespace stl 624 | 625 | /*---------------------------------------------------------------------*/ 626 | /* Wrapper for the cord data structure 627 | * 628 | * This data structure is included in the Boehm–Demers–Weiser garbage 629 | * collector. 630 | */ 631 | 632 | //! \warning Safe use of cord requires a call to `GC_INIT()` prior to use 633 | 634 | #ifdef HAVE_CORD 635 | template 636 | class cord_wrapper { 637 | public: 638 | typedef CORD container_t; 639 | typedef Item value_type; 640 | typedef size_t size_type; 641 | 642 | mutable container_t v; 643 | 644 | static container_t chars(size_t nb, value_type val) { 645 | return CORD_chars(val.get_char(), nb); 646 | } 647 | 648 | value_type fetch(size_t pos) const { 649 | assert(pos < size()); 650 | return value_type(CORD_fetch(v, (int)pos)); 651 | } 652 | 653 | cord_wrapper() { 654 | v = CORD_EMPTY; 655 | } 656 | 657 | cord_wrapper(size_t nb, value_type val) { 658 | v = chars(nb, val); 659 | } 660 | 661 | bool empty() const { 662 | return v == CORD_EMPTY; 663 | } 664 | 665 | void push_back(Item i) { 666 | v = CORD_cat(v, chars(1, i)); 667 | } 668 | 669 | Item pop_back() { 670 | Item i = fetch(size() - 1); 671 | v = CORD_substr(v, 0, size() - 1); 672 | return i; 673 | } 674 | 675 | void push_front(Item i) { 676 | v = CORD_cat(chars(1, i), v); 677 | } 678 | 679 | Item pop_front() { 680 | Item i = fetch(0); 681 | v = CORD_substr(v, 1, size() - 1); 682 | return i; 683 | } 684 | 685 | size_t size() const { 686 | return CORD_len(v); 687 | } 688 | 689 | typedef int iterator; 690 | 691 | iterator begin() const { 692 | return 0; 693 | } 694 | 695 | iterator end() const { 696 | return size() + 1; 697 | } 698 | 699 | iterator insert(iterator pos, const Item& val) { 700 | cord_wrapper dst; 701 | transfer_from_back_to_front_by_position(dst, pos); 702 | dst.push_front(val); 703 | transfer_to_back(dst); 704 | } 705 | 706 | void clear() { 707 | v = CORD_EMPTY; 708 | } 709 | 710 | void pushn_back(value_type* vs, size_t nb) { 711 | for (size_t i = 0; i < nb; i++) 712 | push_back(vs[i]); 713 | } 714 | 715 | void pushn_back(const value_type v, size_t nb) { 716 | for (size_t i = 0; i < nb; i++) 717 | push_back(v); 718 | } 719 | 720 | void popn_back(value_type* vs, size_t nb) { 721 | for (size_t i = 0; i < nb; i++) 722 | pop_back(); 723 | } 724 | 725 | value_type operator[](int ix) const { 726 | return fetch((size_t)ix); 727 | } 728 | 729 | value_type operator[](size_t ix) const { 730 | return fetch(ix); 731 | } 732 | 733 | template 734 | void for_each(const Loop_body& body) { 735 | for (size_t i = 0; i < size(); i++) 736 | body(i, v[i]); 737 | } 738 | 739 | void transfer_to_back(cord_wrapper& r) { 740 | v = CORD_cat(v, r.v); 741 | r.v = CORD_EMPTY; 742 | } 743 | 744 | void transfer_from_back_to_front_by_position(cord_wrapper& dst, iterator it) { 745 | dst.v = CORD_substr(v, it, size()); 746 | v = CORD_substr(v, 0, it); 747 | } 748 | 749 | void swap(cord_wrapper& other) { 750 | std::swap(v, other.v); 751 | } 752 | 753 | }; 754 | #endif 755 | 756 | } // end namespace data 757 | } // end namespace pasl 758 | 759 | 760 | /***********************************************************************/ 761 | 762 | #endif /*! _PASL_DATA_CONTAINER_H_ */ 763 | -------------------------------------------------------------------------------- /bench/do_fifo.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define BOOTNEW 1 3 | 4 | #include 5 | 6 | #include "cmdline.hpp" 7 | #include "atomic.hpp" 8 | #include "microtime.hpp" 9 | 10 | #include "container.hpp" 11 | #include "fixedcapacity.hpp" 12 | #include "chunkedseq.hpp" 13 | #include "cachedmeasure.hpp" 14 | 15 | 16 | using namespace pasl; 17 | using namespace pasl::util; 18 | using namespace deepsea; 19 | namespace chunkedseq = pasl::data::chunkedseq; 20 | 21 | /***********************************************************************/ 22 | 23 | typedef size_t result_t; 24 | 25 | 26 | result_t res = 0; 27 | double exec_time; 28 | 29 | /*---------------------------------------------------------------------*/ 30 | 31 | class bytes_8 { 32 | public: 33 | uint64_t data; 34 | bytes_8() { } 35 | bytes_8(char c) { 36 | data = (uint64_t)c; 37 | } 38 | bytes_8(size_t i) { 39 | data = i; 40 | } 41 | size_t get() const { 42 | return data; 43 | } 44 | char get_char() const { 45 | return (char) (data % 256); 46 | } 47 | bool operator==(const bytes_8 other) { 48 | return data == other.data; 49 | } 50 | }; 51 | 52 | 53 | /*---------------------------------------------------------------------*/ 54 | /* Scenarios */ 55 | 56 | 57 | // #define FIFO_LIFO_ONLY_COUNT_POP 1 58 | 59 | template 60 | void scenario_lifo() { 61 | typedef typename Datastruct::value_type value_type; 62 | size_t nb_total = (size_t) cmdline::parse_or_default_long("n", 100000000); 63 | size_t repeat = (size_t) cmdline::parse_or_default_long("r", 1000); 64 | size_t block = nb_total / repeat; 65 | printf("length %lld\n",(long long int)block); 66 | uint64_t start_time = microtime::now(); 67 | Datastruct d; 68 | res = 0; 69 | for (size_t j = 0; j < repeat; j++) { 70 | for (size_t i = 0; i < block; i++) { 71 | d.push_back(value_type(i)); 72 | res += i; 73 | } 74 | for (size_t i = 0; i < block; i++) { 75 | res += d.pop_back().get(); 76 | } 77 | } 78 | exec_time = microtime::seconds_since(start_time); 79 | } 80 | 81 | template 82 | void scenario_fifo() { 83 | typedef typename Datastruct::value_type value_type; 84 | size_t nb_total = (size_t) cmdline::parse_or_default_long("n", 100000000); 85 | size_t repeat = (size_t) cmdline::parse_or_default_long("r", 1000); 86 | size_t block = nb_total / repeat; 87 | printf("length %lld\n",(long long int)block); 88 | uint64_t start_time = microtime::now(); 89 | Datastruct d; 90 | res = 0; 91 | for (size_t j = 0; j < repeat; j++) { 92 | for (size_t i = 0; i < block; i++) { 93 | d.push_back(value_type(i)); 94 | res += i; 95 | } 96 | for (size_t i = 0; i < block; i++) { 97 | res += d.pop_front().get(); 98 | } 99 | } 100 | exec_time = microtime::seconds_since(start_time); 101 | } 102 | 103 | 104 | 105 | /*---------------------------------------------------------------------*/ 106 | // dispatch sequences 107 | 108 | using Item = bytes_8; 109 | 110 | 111 | using seq1_type = pasl::data::stl::deque_seq; 112 | 113 | using seq2_type = chunkedseq::bootstrapped::deque< 114 | Item, 115 | 512, 116 | pasl::data::cachedmeasure::trivial, 117 | data::fixedcapacity::heap_allocated::ringbuffer_ptr >; 118 | 119 | using fftree_deque_type = chunkedseq::ftree::deque< 120 | Item, 121 | 512, 122 | pasl::data::cachedmeasure::trivial, 123 | data::fixedcapacity::heap_allocated::ringbuffer_ptr >; 124 | 125 | #if 0 126 | 127 | using seq3_type = chunkedseq::bootstrapped::deque< 128 | Item, 129 | 512, 130 | pasl::data::cachedmeasure::trivial, 131 | data::fixedcapacity::heap_allocated::ringbuffer_ptrx >; 132 | #endif 133 | 134 | 135 | int main(int argc, char** argv) { 136 | cmdline::set(argc, argv); 137 | res = 0; 138 | 139 | std::string sequence = cmdline::parse_or_default_string("sequence", "stl_deque"); 140 | std::string scenario = cmdline::parse_or_default_string("scenario", "fifo"); 141 | int chunk_size = cmdline::parse_or_default_int("chunk_size", 512); 142 | if (chunk_size != 512) { 143 | printf("not valid chunk size\n"); 144 | exit(1); 145 | } 146 | 147 | if (scenario == "fifo") { 148 | if (sequence == "stl_deque") { 149 | scenario_fifo(); 150 | } else 151 | if (sequence == "chunkedseq") { // ptr 152 | scenario_fifo(); 153 | #if 0 154 | } else if (sequence == "chunkedseq_ptrx") { 155 | scenario_fifo(); 156 | #endif 157 | } else if (sequence == "chunkedftree") { 158 | scenario_fifo(); 159 | } else { 160 | printf("not valid sequence\n"); 161 | exit(1); 162 | } 163 | } 164 | else if (scenario == "lifo") { 165 | if (sequence == "stl_deque") { 166 | scenario_lifo(); 167 | } else 168 | if (sequence == "chunkedseq") { 169 | scenario_lifo(); 170 | #if 0 171 | } else if (sequence == "chunkedseq_ptrx") { 172 | scenario_fifo(); 173 | #endif 174 | } else if (sequence == "chunkedftree") { 175 | scenario_fifo(); 176 | } else { 177 | printf("not valid sequence\n"); 178 | exit(1); 179 | } 180 | } 181 | 182 | printf ("exectime %lf\n", exec_time); 183 | printf("result %lld\n", (long long)res); 184 | 185 | return 0; 186 | } 187 | 188 | 189 | 190 | 191 | /***********************************************************************/ 192 | -------------------------------------------------------------------------------- /bench/microtime.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "microtime.hpp" 4 | #include 5 | #include 6 | 7 | namespace pasl { 8 | namespace util { 9 | namespace microtime { 10 | 11 | /***********************************************************************/ 12 | 13 | microtime_t now() { 14 | struct timeval tv; 15 | gettimeofday(&tv, NULL); 16 | return 1000000l * ((microtime_t) tv.tv_sec) + ((microtime_t) tv.tv_usec); 17 | } 18 | 19 | microtime_t diff(microtime_t t1, microtime_t t2) { 20 | return t2 - t1; 21 | } 22 | 23 | microtime_t since(microtime_t t) { 24 | return diff(t, now()); 25 | } 26 | 27 | double seconds(microtime_t t) { 28 | return ((double) t) / 1000000l; 29 | } 30 | 31 | double seconds_since(microtime_t t) { 32 | return seconds(since(t)); 33 | } 34 | 35 | double microseconds_since(microtime_t t) { 36 | return (double) since(t); 37 | } 38 | 39 | // wait for a very little time 40 | 41 | void microsleep(double t) { 42 | for (int k = 0; k < (int) (10*t); k++) { 43 | for (int j = k; j < k + 5; j++) 44 | (k/(j+1)); 45 | } 46 | } 47 | 48 | /***********************************************************************/ 49 | 50 | } // namespace 51 | } // namespace 52 | } // namespace 53 | 54 | -------------------------------------------------------------------------------- /bench/microtime.hpp: -------------------------------------------------------------------------------- 1 | /* COPYRIGHT (c) 2014 Umut Acar, Arthur Chargueraud, and Michael 2 | * Rainey 3 | * All rights reserved. 4 | * 5 | * \file microtime.hpp 6 | * \brief Interface for system time; unit is microseconds 7 | * 8 | */ 9 | 10 | #ifndef _PASL_UTIL_MICROTIME_H_ 11 | #define _PASL_UTIL_MICROTIME_H_ 12 | 13 | #include 14 | 15 | namespace pasl { 16 | namespace util { 17 | namespace microtime { 18 | 19 | /***********************************************************************/ 20 | 21 | typedef uint64_t microtime_t; 22 | 23 | /* Convert in seconds */ 24 | 25 | double seconds(microtime_t t); 26 | 27 | /* Get current time in microseconds */ 28 | 29 | microtime_t now(); 30 | 31 | /* Compute difference between two times, assert t2>=t1 */ 32 | 33 | microtime_t diff(microtime_t t1, microtime_t t2); 34 | 35 | /* Compute difference between a given time and now; 36 | since(t) is equivalent to diff(t, now()) */ 37 | 38 | microtime_t since(microtime_t t); 39 | 40 | /* Compute difference directly in seconds */ 41 | 42 | double seconds_since(microtime_t t); 43 | 44 | /* Same for microseconds */ 45 | 46 | double microseconds_since(microtime_t t); 47 | 48 | 49 | // todo: microsleep( 50 | void microsleep(double t); 51 | 52 | // todo: present as class! 53 | 54 | 55 | /***********************************************************************/ 56 | 57 | } // namespace 58 | } // namespace 59 | } // namespace 60 | 61 | /***********************************************************************/ 62 | 63 | /* For debugging purposes, you can measure the time taken by a piece 64 | of code by writing 65 | MICROTIME_START; 66 | my_code 67 | MICROTIME_END("my_code_name"); 68 | */ 69 | 70 | #define MICROTIME_START \ 71 | microtime::microtime_t __microtime = microtime::now() 72 | #define MICROTIME_END(name) \ 73 | printf("time_%s %lf\n", name, microtime::seconds_since(__microtime)) 74 | 75 | 76 | 77 | #endif /*! _PASL_UTIL_MICROTIME_H_ */ 78 | 79 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | 2 | %.example: %.cpp 3 | ./extract_snippets.sh $< $@ 4 | 5 | %.example: %.hpp 6 | ./extract_snippets.sh $< $@ 7 | 8 | BUILDDIR := snippets 9 | SOURCEDIR := ../examples/ 10 | SOURCES := $(shell find $(SOURCEDIR) -name '*.cpp') \ 11 | ../include/measure.hpp \ 12 | ../include/fixedcapacitybase.hpp \ 13 | ../examples/map.hpp \ 14 | ../include/segment.hpp \ 15 | ../include/algebra.hpp \ 16 | ../examples/map_1.cpp \ 17 | ../include/cachedmeasure.hpp 18 | EXAMPLES := $(SOURCES:%.cpp=%.example) $(SOURCES:%.hpp=%.example) 19 | 20 | build: chunkedseq.html5 chunkedseq.pdf 21 | 22 | chunkedseq.html: chunkedseq.md $(EXAMPLES) 23 | pandoc --filter includes.hs chunkedseq.md --toc --number-sections -s -c chunkedseq.css -o chunkedseq.html 24 | 25 | chunkedseq.pdf: chunkedseq.md $(EXAMPLES) 26 | pandoc --filter includes.hs chunkedseq.md --toc --number-sections -s -o chunkedseq.pdf 27 | 28 | WEB=~/Work/deepsea-web/chunkedseq/ 29 | 30 | publish: chunkedseq.html5 chunkedseq.pdf 31 | cp chunkedseq.html chunkedseq.pdf chunkedseq.css $(WEB)/doc 32 | (cd $(WEB) && make publish) 33 | 34 | clean_examples: 35 | rm -f ../examples/*.example.* ../include/*.example.* ../examples/*.example ../include/*.example 36 | 37 | clean: clean_examples 38 | rm -f chunkedseq.html5 chunkedseq.pdf 39 | -------------------------------------------------------------------------------- /doc/chunkedseq.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: auto; 3 | padding-right: 1em; 4 | padding-left: 1em; 5 | max-width: 40em; 6 | } 7 | pre { 8 | border: 1px dotted gray; 9 | color: #1111111; 10 | padding: 0.5em; 11 | } 12 | code { 13 | font-family: monospace; 14 | } 15 | h1 a, h2 a, h3 a, h4 a, h5 a { 16 | text-decoration: none; 17 | } 18 | h1, h2, h3, h4, h5 { } 19 | h1 { 20 | font-size: 180%; 21 | } 22 | 23 | h2 { 24 | font-size: 120%; 25 | } 26 | 27 | h3 { 28 | font-size: 100%; 29 | } 30 | 31 | h4 { 32 | font-size: 90%; 33 | font-style: italic; 34 | } 35 | 36 | h5 { 37 | font-size: 90%; 38 | font-style: italic; 39 | } 40 | 41 | h1.title { 42 | font-size: 250%; 43 | text-align: center; 44 | border: none; 45 | } 46 | 47 | h2.author { 48 | font-size: 120%; 49 | text-align: center; 50 | border: none; 51 | } 52 | 53 | h3.date { 54 | font-size: 100%; 55 | text-align: center; 56 | border: none; 57 | } 58 | 59 | 60 | dt code { 61 | font-weight: bold; 62 | } 63 | dd p { 64 | margin-top: 0; 65 | } 66 | 67 | h1.title { 68 | font-size: 250%; 69 | text-align: center; 70 | border: none; 71 | } 72 | 73 | .author { 74 | font-size: 1.2em; 75 | text-align: center; 76 | } 77 | 78 | .date { 79 | font-size: 100%; 80 | text-align: center; 81 | border: none; 82 | } 83 | 84 | table { 85 | width: 100%; 86 | } 87 | 88 | td, th { 89 | vertical-align: top; 90 | vertical-align: baseline; 91 | padding-left: 0.5em; 92 | padding-right: 0.5em; 93 | padding-top: 0.2em; 94 | padding-bottom: 0.2em; 95 | } 96 | -------------------------------------------------------------------------------- /doc/extract_snippets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script extracts from a specified C++ file all ranges of source 4 | # lines that occur between Doxygen code-snippet delimiters. For 5 | # example, suppose that our input file, namely test.cpp contains the 6 | # following: 7 | # 8 | # int foo() { 9 | # return 0; 10 | # } 11 | # 12 | # //! [bar] 13 | # int bar() { 14 | # return 1; 15 | # } 16 | # //! [bar] 17 | # 18 | # //! [baz] 19 | # int baz() { 20 | # return 2; 21 | # } 22 | # //! [baz] 23 | # 24 | # Now, if we call 25 | # 26 | # $ extract_code_snippets.sh test.cpp test.out 27 | # 28 | # then, the script will first perform `touch test.out`, and the script 29 | # will then create two files, namely "test.out.bar" and 30 | # "test.out.baz". Each of these latter two files will contain the 31 | # source lines that appear between the corresponding delimiters. For 32 | # example, the contents of test.out.bar will be: 33 | # 34 | # int bar() { 35 | # return 1; 36 | # } 37 | # 38 | 39 | SOURCE_FILE_NAME=$1 40 | OUT_FILE_NAME=$2 41 | 42 | touch $OUT_FILE_NAME 43 | 44 | p=0 45 | block_name="" 46 | while IFS='' read -r line 47 | do 48 | case $line in 49 | \/\/!*) 50 | p=$((1-$p)); 51 | str=$line 52 | str1=${str##*\[} 53 | str2=${str1%%\]*} 54 | block_name=$str2 55 | continue;; 56 | esac 57 | filename="$OUT_FILE_NAME.$block_name" 58 | if [ "$p" -eq 1 ]; then 59 | echo "$line" >> $filename 60 | fi 61 | done < $SOURCE_FILE_NAME 62 | 63 | -------------------------------------------------------------------------------- /doc/includes.hs: -------------------------------------------------------------------------------- 1 | import Text.Pandoc.JSON 2 | 3 | doInclude :: Block -> IO Block 4 | doInclude cb@(CodeBlock (id, classes, namevals) contents) = 5 | case lookup "include" namevals of 6 | Just f -> return . (CodeBlock (id, classes, namevals)) =<< readFile f 7 | Nothing -> return cb 8 | doInclude x = return x 9 | 10 | main :: IO () 11 | main = toJSONFilter doInclude -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | INCLUDES = -I ../include 2 | 3 | CC = g++ -std=c++11 4 | 5 | %.exe: %.cpp 6 | $(CC) $(INCLUDES) $< -o $@ 7 | 8 | clean: 9 | rm -f *.exe 10 | -------------------------------------------------------------------------------- /examples/chunkedseq_1.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_1.cpp 10 | * \example chunkedseq_1.cpp 11 | * \ingroup chunkedseq 12 | * 13 | */ 14 | 15 | //! [chunkedseq_example1] 16 | #include 17 | 18 | #include "chunkedseq.hpp" 19 | 20 | using cbdeque = pasl::data::chunkedseq::bootstrapped::deque; 21 | 22 | // moves items which satisfy a given predicate p from src to dst 23 | // preserving original order of items in src 24 | template 25 | void pkeep_if(cbdeque& dst, cbdeque& src, const Predicate_function& p) { 26 | 27 | const int cutoff = 8096; 28 | 29 | long sz = src.size(); 30 | 31 | if (sz <= cutoff) { 32 | 33 | // compute result in a sequential fashion 34 | while (sz-- > 0) { 35 | long item = src.pop_back(); 36 | if (p(item)) 37 | dst.push_front(item); 38 | } 39 | 40 | } else { 41 | 42 | cbdeque src2; 43 | cbdeque dst2; 44 | 45 | // divide the input evenly in two halves 46 | size_t mid = sz / 2; 47 | src.split(mid, src2); 48 | 49 | // recurse on subproblems 50 | // calls can execute in parallel 51 | pkeep_if(dst, src, p); 52 | pkeep_if(dst2, src2, p); 53 | 54 | // combine results (after parallel calls complete) 55 | dst.concat(dst2); 56 | 57 | } 58 | } 59 | 60 | int main(int argc, const char * argv[]) { 61 | 62 | cbdeque src; 63 | cbdeque dst; 64 | 65 | const long n = 1000000; 66 | 67 | // fill the source container with [1, ..., 2n] 68 | for (long i = 1; i <= 2*n; i++) 69 | src.push_back(i); 70 | 71 | // leave src empty and dst = [1, 3, 5, ... n-1] 72 | pkeep_if(dst, src, [] (long x) { return x%2 == 1; }); 73 | 74 | assert(src.empty()); 75 | assert(dst.size() == n); 76 | 77 | // calculate the sum 78 | long sum = 0; 79 | while (! dst.empty()) 80 | sum += dst.pop_front(); 81 | 82 | // the sum of n consecutive odd integers starting from 1 equals n^2 83 | assert(sum == n*n); 84 | std::cout << "sum = " << sum << std::endl; 85 | 86 | return 0; 87 | 88 | } 89 | //! [chunkedseq_example1] 90 | -------------------------------------------------------------------------------- /examples/chunkedseq_2.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_2.cpp 10 | * \example chunkedseq_2.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [deque_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | int main(int argc, const char * argv[]) { 24 | 25 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 26 | 27 | const int nb = 5; 28 | 29 | mydeque_type mydeque; 30 | 31 | for (int i = 0; i < nb; i++) 32 | mydeque.push_back(i); 33 | for (int i = 0; i < nb; i++) 34 | mydeque.push_front(nb+i); 35 | 36 | assert(mydeque.size() == 2*nb); 37 | 38 | std::cout << "mydeque contains:"; 39 | for (int i = 0; i < 2*nb; i++) { 40 | int v = (i % 2) ? mydeque.pop_front() : mydeque.pop_back(); 41 | std::cout << " " << v; 42 | } 43 | std::cout << std::endl; 44 | 45 | assert(mydeque.empty()); 46 | 47 | return 0; 48 | 49 | } 50 | //! [deque_example] 51 | -------------------------------------------------------------------------------- /examples/chunkedseq_3.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_3.cpp 10 | * \example chunkedseq_3.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [stack_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | int main(int argc, const char * argv[]) { 24 | 25 | using mystack_type = pasl::data::chunkedseq::bootstrapped::stack; 26 | 27 | mystack_type mystack = { 0, 1, 2, 3, 4 }; 28 | 29 | std::cout << "mystack contains:"; 30 | while (! mystack.empty()) 31 | std::cout << " " << mystack.pop_back(); 32 | std::cout << std::endl; 33 | 34 | return 0; 35 | 36 | } 37 | //! [stack_example] 38 | -------------------------------------------------------------------------------- /examples/chunkedseq_4.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_4.cpp 10 | * \example chunkedseq_4.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [bag_example] 17 | #include 18 | #include 19 | 20 | #include "chunkedbag.hpp" 21 | 22 | int main(int argc, const char * argv[]) { 23 | 24 | using mybag_type = pasl::data::chunkedseq::bootstrapped::bagopt; 25 | 26 | mybag_type mybag = { 0, 1, 2, 3, 4 }; 27 | 28 | std::cout << "mybag contains:"; 29 | while (! mybag.empty()) 30 | std::cout << " " << mybag.pop(); 31 | std::cout << std::endl; 32 | 33 | return 0; 34 | 35 | } 36 | //! [bag_example] 37 | -------------------------------------------------------------------------------- /examples/chunkedseq_5.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_5.cpp 10 | * \example chunkedseq_5.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [split_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 24 | 25 | static 26 | void myprint(mydeque_type& mydeque) { 27 | auto it = mydeque.begin(); 28 | while (it != mydeque.end()) 29 | std::cout << " " << *it++; 30 | std::cout << std::endl; 31 | } 32 | 33 | int main(int argc, const char * argv[]) { 34 | 35 | mydeque_type mydeque = { 0, 1, 2, 3, 4, 5 }; 36 | mydeque_type mydeque2; 37 | 38 | mydeque.split(size_t(3), mydeque2); 39 | 40 | mydeque.pop_back(); 41 | mydeque.push_back(8888); 42 | 43 | mydeque2.pop_front(); 44 | mydeque2.push_front(9999); 45 | 46 | std::cout << "Just after split:" << std::endl; 47 | std::cout << "contents of mydeque:"; 48 | myprint(mydeque); 49 | std::cout << "contents of mydeque2:"; 50 | myprint(mydeque2); 51 | 52 | mydeque.concat(mydeque2); 53 | 54 | std::cout << "Just after merge:" << std::endl; 55 | std::cout << "contents of mydeque:"; 56 | myprint(mydeque); 57 | std::cout << "contents of mydeque2:"; 58 | myprint(mydeque2); 59 | 60 | return 0; 61 | 62 | } 63 | //! [split_example] 64 | -------------------------------------------------------------------------------- /examples/chunkedseq_6.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_6.cpp 10 | * \example chunkedseq_6.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [pcopy_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | template 24 | void pcopy(typename Chunkedseq::iterator first, 25 | typename Chunkedseq::iterator last, 26 | Chunkedseq& destination) { 27 | using iterator = typename Chunkedseq::iterator; 28 | using ptr = typename Chunkedseq::const_pointer; 29 | 30 | const long cutoff = 8192; 31 | 32 | long sz = last.size() - first.size(); 33 | 34 | if (sz <= cutoff) { 35 | 36 | // compute result in a sequential fashion 37 | Chunkedseq::for_each_segment(first, last, [&] (ptr lo, ptr hi) { 38 | destination.pushn_back(lo, hi-lo); 39 | }); 40 | 41 | } else { 42 | 43 | // select split position to be the median 44 | iterator mid = first + (sz/2); 45 | 46 | Chunkedseq destination2; 47 | 48 | // recurse on subproblems 49 | // calls can execute in parallel 50 | pcopy(first, mid, destination); 51 | pcopy(mid, last, destination2); 52 | 53 | // combine results 54 | destination.concat(destination2); 55 | 56 | } 57 | } 58 | 59 | int main(int argc, const char * argv[]) { 60 | 61 | const int chunk_size = 2; 62 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 63 | 64 | mydeque_type mydeque = { 0, 1, 2, 3, 4, 5 }; 65 | mydeque_type mydeque2; 66 | 67 | pcopy(mydeque.begin(), mydeque.end(), mydeque2); 68 | 69 | std::cout << "mydeque2 contains:"; 70 | auto p = mydeque2.begin(); 71 | while (p != mydeque2.end()) 72 | std::cout << " " << *p++; 73 | std::cout << std::endl; 74 | 75 | return 0; 76 | 77 | } 78 | //! [pcopy_example] -------------------------------------------------------------------------------- /examples/chunkedseq_7.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file chunkedseq_7.cpp 10 | * \example chunkedseq_7.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [pcopy_if_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | template 24 | void pcopy_if(typename Chunkedseq::iterator first, 25 | typename Chunkedseq::iterator last, 26 | Chunkedseq& destination, 27 | const UnaryPredicate& pred) { 28 | using iterator = typename Chunkedseq::iterator; 29 | using value_type = typename Chunkedseq::value_type; 30 | using ptr = typename Chunkedseq::const_pointer; 31 | 32 | const long cutoff = 8192; 33 | 34 | long sz = last.size() - first.size(); 35 | 36 | if (sz <= cutoff) { 37 | 38 | // compute result in a sequential fashion 39 | Chunkedseq::for_each_segment(first, last, [&] (ptr lo, ptr hi) { 40 | for (ptr p = lo; p < hi; p++) { 41 | value_type v = *p; 42 | if (pred(v)) 43 | destination.push_back(v); 44 | } 45 | }); 46 | 47 | } else { 48 | 49 | // select split position to be the median 50 | iterator mid = first + (sz/2); 51 | 52 | Chunkedseq destination2; 53 | 54 | // recurse on subproblems 55 | // calls can execute in parallel 56 | pcopy_if(first, mid, destination, pred); 57 | pcopy_if(mid, last, destination2, pred); 58 | 59 | destination.concat(destination2); 60 | } 61 | } 62 | 63 | int main(int argc, const char * argv[]) { 64 | 65 | const int chunk_size = 2; 66 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 67 | 68 | mydeque_type mydeque = { 0, 1, 2, 3, 4, 5 }; 69 | mydeque_type mydeque2; 70 | 71 | pcopy_if(mydeque.begin(), mydeque.end(), mydeque2, [] (int i) { return i%2==0; }); 72 | 73 | std::cout << "mydeque2 contains:"; 74 | auto p = mydeque2.begin(); 75 | while (p != mydeque2.end()) 76 | std::cout << " " << *p++; 77 | std::cout << std::endl; 78 | 79 | return 0; 80 | 81 | } 82 | //! [pcopy_if_example] -------------------------------------------------------------------------------- /examples/iterator_1.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file iterator.cpp 10 | * \example iterator.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [iterator_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | int main(int argc, const char * argv[]) { 24 | 25 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 26 | using iterator = typename mydeque_type::iterator; 27 | 28 | mydeque_type mydeque = { 0, 1, 2, 3, 4 }; 29 | 30 | std::cout << "mydeque contains:"; 31 | iterator it = mydeque.begin(); 32 | while (it != mydeque.end()) 33 | std::cout << " " << *it++; 34 | 35 | std::cout << std::endl; 36 | 37 | return 0; 38 | 39 | } 40 | //! [iterator_example] -------------------------------------------------------------------------------- /examples/map.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief STL-style map data structure 9 | * \file map.hpp 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "chunkedseq.hpp" 18 | 19 | #ifndef _PASL_DATA_MAP_H_ 20 | #define _PASL_DATA_MAP_H_ 21 | 22 | namespace pasl { 23 | namespace data { 24 | namespace map { 25 | 26 | /***********************************************************************/ 27 | 28 | /*---------------------------------------------------------------------*/ 29 | //! [option] 30 | template 31 | class option { 32 | public: 33 | 34 | using self_type = option; 35 | 36 | Item item; 37 | bool no_item; 38 | 39 | option() 40 | : item(), no_item(true) { } 41 | 42 | option(const Item& item) 43 | : item(item), no_item(false) { } 44 | 45 | option(const option& other) 46 | : item(other.item), no_item(other.no_item) { } 47 | 48 | void swap(option& other) { 49 | Item_swap::swap(item, other.item); 50 | std::swap(no_item, other.no_item); 51 | } 52 | 53 | bool operator<(const self_type& y) const { 54 | if (no_item && y.no_item) 55 | return false; 56 | if (no_item) 57 | return true; 58 | if (y.no_item) 59 | return false; 60 | return item < y.item; 61 | } 62 | 63 | bool operator>=(const self_type& y) const { 64 | return ! (*this < y); 65 | } 66 | 67 | }; 68 | //! [option] 69 | 70 | /*---------------------------------------------------------------------*/ 71 | //! [get_key_of_last_item] 72 | 73 | template 74 | class get_key_of_last_item { 75 | public: 76 | 77 | using value_type = Item; 78 | using key_type = typename value_type::first_type; 79 | using measured_type = Measured; 80 | 81 | measured_type operator()(const value_type& v) const { 82 | key_type key = v.first; 83 | return measured_type(key); 84 | } 85 | 86 | measured_type operator()(const value_type* lo, const value_type* hi) const { 87 | if (hi - lo == 0) 88 | return measured_type(); 89 | const value_type* last = hi - 1; 90 | key_type key = last->first; 91 | return measured_type(key); 92 | } 93 | }; 94 | //! [get_key_of_last_item] 95 | 96 | /*---------------------------------------------------------------------*/ 97 | //! [take_right_if_nonempty] 98 | template 99 | class take_right_if_nonempty { 100 | public: 101 | 102 | using value_type = Option; 103 | 104 | static constexpr bool has_inverse = false; 105 | 106 | static value_type identity() { 107 | return value_type(); 108 | } 109 | 110 | static value_type combine(value_type left, value_type right) { 111 | if (right.no_item) 112 | return left; 113 | return right; 114 | } 115 | 116 | static value_type inverse(value_type x) { 117 | // cannot happen 118 | return identity(); 119 | } 120 | 121 | }; 122 | //! [take_right_if_nonempty] 123 | 124 | /*---------------------------------------------------------------------*/ 125 | 126 | //! [map_cache] 127 | template 128 | class map_cache { 129 | public: 130 | 131 | using size_type = Size; 132 | using value_type = Item; 133 | using key_type = typename value_type::first_type; 134 | using option_type = option; 135 | using algebra_type = take_right_if_nonempty; 136 | using measured_type = typename algebra_type::value_type; // = option_type 137 | using measure_type = get_key_of_last_item; 138 | 139 | static void swap(measured_type& x, measured_type& y) { 140 | x.swap(y); 141 | } 142 | 143 | }; 144 | //! [map_cache] 145 | 146 | /*---------------------------------------------------------------------*/ 147 | //! [swap] 148 | template 149 | class std_swap { 150 | public: 151 | 152 | static void swap(Item& x, Item& y) { 153 | std::swap(x, y); 154 | } 155 | 156 | }; 157 | //! [swap] 158 | 159 | /*---------------------------------------------------------------------*/ 160 | //! [map] 161 | template , 164 | class Key_swap = std_swap, 165 | class Alloc = std::allocator >, 166 | int chunk_capacity = 8 167 | > 168 | class map { 169 | public: 170 | 171 | using key_type = Key; 172 | using mapped_type = Item; 173 | using value_type = std::pair; 174 | using key_compare = Compare; 175 | using allocator_type = Alloc; 176 | using reference = value_type&; 177 | using const_reference = const value_type&; 178 | using pointer = value_type*; 179 | using const_pointer = const value_type*; 180 | using difference_type = ptrdiff_t; 181 | using size_type = size_t; 182 | using key_swap_type = Key_swap; 183 | 184 | private: 185 | 186 | using cache_type = map_cache; 187 | using container_type = chunkedseq::bootstrapped::deque; 188 | using option_type = typename cache_type::measured_type; 189 | 190 | public: 191 | 192 | using iterator = typename container_type::iterator; 193 | 194 | private: 195 | 196 | // invariant: items in seq are sorted in ascending order by their key values 197 | mutable container_type seq; 198 | mutable iterator it; 199 | 200 | iterator upper(const key_type& k) const { 201 | option_type target(k); 202 | it.search_by([target] (const option_type& key) { 203 | return target >= key; 204 | }); 205 | return it; 206 | } 207 | 208 | public: 209 | 210 | map() { 211 | it = seq.begin(); 212 | } 213 | 214 | map(const map& other) 215 | : seq(other.seq) { 216 | it = seq.begin(); 217 | } 218 | 219 | size_type size() const { 220 | return seq.size(); 221 | } 222 | 223 | bool empty() const { 224 | return size() == 0; 225 | } 226 | 227 | iterator find(const key_type& k) const { 228 | iterator it = upper(k); 229 | return ((*it).first == k) ? it : seq.end(); 230 | } 231 | 232 | mapped_type& operator[](const key_type& k) const { 233 | it = upper(k); 234 | if (it == seq.end()) { 235 | // key k is larger than any key current in seq 236 | value_type val; 237 | val.first = k; 238 | seq.push_back(val); 239 | it = seq.end()-1; 240 | } else if ((*it).first != k) { 241 | // iterator it points to the first key that is less than k 242 | value_type val; 243 | val.first = k; 244 | it = seq.insert(it, val); 245 | } 246 | return (*it).second; 247 | } 248 | 249 | void erase(iterator it) { 250 | if (it == seq.end()) 251 | return; 252 | if (it == seq.end()-1) { 253 | seq.pop_front(); 254 | return; 255 | } 256 | seq.erase(it, it+1); 257 | } 258 | 259 | size_type erase(const key_type& k) { 260 | size_type nb = seq.size(); 261 | erase(find(k)); 262 | return nb - seq.size(); 263 | } 264 | 265 | std::ostream& stream(std::ostream& out) const { 266 | out << "["; 267 | size_type sz = size(); 268 | seq.for_each([&] (value_type v) { 269 | out << "(" << v.first << "," << v.second << ")"; 270 | if (sz-- != 1) 271 | out << ","; 272 | }); 273 | return out << "]"; 274 | } 275 | 276 | iterator begin() const { 277 | return seq.begin(); 278 | } 279 | 280 | iterator end() const { 281 | return seq.end(); 282 | } 283 | 284 | void check() const { 285 | seq.check(); 286 | } 287 | 288 | }; 289 | //! [map] 290 | 291 | /***********************************************************************/ 292 | 293 | } // end namespace 294 | } // end namespace 295 | } // end namespace 296 | 297 | #endif /*! _PASL_DATA_MAP_H_ */ 298 | -------------------------------------------------------------------------------- /examples/map_1.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file map_1.cpp 10 | * \example map_1.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [map_example] 17 | // accessing mapped values 18 | #include 19 | #include 20 | 21 | #include "map.hpp" 22 | 23 | int main () { 24 | pasl::data::map::map mymap; 25 | 26 | mymap['a']="an element"; 27 | mymap['b']="another element"; 28 | mymap['c']=mymap['b']; 29 | 30 | std::cout << "mymap['a'] is " << mymap['a'] << '\n'; 31 | std::cout << "mymap['b'] is " << mymap['b'] << '\n'; 32 | std::cout << "mymap['c'] is " << mymap['c'] << '\n'; 33 | std::cout << "mymap['d'] is " << mymap['d'] << '\n'; 34 | 35 | std::cout << "mymap now contains " << mymap.size() << " elements.\n"; 36 | 37 | return 0; 38 | } 39 | //! [map_example] -------------------------------------------------------------------------------- /examples/map_2.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file map_1.cpp 10 | * \example map_1.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [map_example2] 17 | // accessing mapped values 18 | #include 19 | #include 20 | 21 | #include "map.hpp" 22 | 23 | int main () 24 | { 25 | pasl::data::map::map mymap; 26 | pasl::data::map::map::iterator it; 27 | 28 | // insert some values: 29 | mymap['a']=10; 30 | mymap['b']=20; 31 | mymap['c']=30; 32 | mymap['d']=40; 33 | mymap['e']=50; 34 | mymap['f']=60; 35 | 36 | it=mymap.find('b'); 37 | mymap.erase (it); // erasing by iterator 38 | 39 | mymap.erase ('c'); // erasing by key 40 | 41 | // show content: 42 | for (it=mymap.begin(); it!=mymap.end(); ++it) 43 | std::cout << (*it).first << " => " << (*it).second << '\n'; 44 | 45 | return 0; 46 | } 47 | //! [map_example2] 48 | -------------------------------------------------------------------------------- /examples/segment_1.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence 9 | * \file segment.cpp 10 | * \example segment.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [segment_example] 17 | #include 18 | #include 19 | #include 20 | 21 | #include "chunkedseq.hpp" 22 | 23 | int main(int argc, const char * argv[]) { 24 | 25 | const int chunk_size = 2; 26 | using mydeque_type = pasl::data::chunkedseq::bootstrapped::deque; 27 | 28 | mydeque_type mydeque = { 0, 1, 2, 3, 4, 5 }; 29 | 30 | std::cout << "mydeque contains:"; 31 | // iterate over the segments in mydeque 32 | mydeque.for_each_segment([&] (int* begin, int* end) { 33 | // iterate over the items in the current segment 34 | int* p = begin; 35 | while (p != end) 36 | std::cout << " " << *p++; 37 | }); 38 | std::cout << std::endl; 39 | 40 | using iterator = typename mydeque_type::iterator; 41 | using segment_type = typename mydeque_type::segment_type; 42 | 43 | // iterate over the items in the segment which contains the item at position 3 44 | iterator it = mydeque.begin() + 3; 45 | segment_type seg = it.get_segment(); 46 | 47 | std::cout << "the segment which contains mydeque[3] contains:"; 48 | int* p = seg.begin; 49 | while (p != seg.end) 50 | std::cout << " " << *p++; 51 | std::cout << std::endl; 52 | 53 | std::cout << "mydeque[3]=" << *seg.middle << std::endl; 54 | 55 | return 0; 56 | 57 | } 58 | //! [segment_example] -------------------------------------------------------------------------------- /examples/trivbootchunkedseq.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Trivial instantiation of bootstrapped chunked sequence 9 | * \file trivbootchunkedseq.hpp 10 | * 11 | */ 12 | 13 | #include "cachedmeasure.hpp" 14 | #include "bootchunkedseq.hpp" 15 | 16 | #ifndef _PASL_DATA_TRIVBOOTCHUNKEDSEQ_H_ 17 | #define _PASL_DATA_TRIVBOOTCHUNKEDSEQ_H_ 18 | 19 | namespace pasl { 20 | namespace data { 21 | namespace chunkedseq { 22 | namespace bootchunkedseq { 23 | 24 | /***********************************************************************/ 25 | 26 | // basic instantiation of bootchunkedseq 27 | template 28 | class triv { 29 | private: 30 | 31 | class top_item_type { 32 | public: 33 | Item value; 34 | top_item_type() { } 35 | top_item_type(const Item& value) 36 | : value(value) { } 37 | size_t get_cached() const { 38 | return 1; 39 | } 40 | }; 41 | 42 | class sized_cached_measure { 43 | public: 44 | 45 | using size_type = size_t; 46 | using value_type = top_item_type*; 47 | using algebra_type = algebra::int_group_under_addition_and_negation; 48 | using measured_type = typename algebra_type::value_type; 49 | 50 | class measure_type { 51 | public: 52 | 53 | measured_type operator()(const value_type& v) const { 54 | return v->get_cached(); 55 | } 56 | 57 | measured_type operator()(const value_type* lo, const value_type* hi) const { 58 | measured_type m = algebra_type::identity(); 59 | for (auto p = lo; p < hi; p++) 60 | m = algebra_type::combine(m, operator()(*p)); 61 | return m; 62 | } 63 | 64 | }; 65 | 66 | static void swap(measured_type& x, measured_type y) { 67 | std::swap(x, y); 68 | } 69 | 70 | }; 71 | 72 | using measure_type = typename sized_cached_measure::measure_type; 73 | 74 | using seq_type = cdeque; 75 | 76 | measure_type meas_fct; 77 | seq_type seq; 78 | 79 | public: 80 | 81 | using size_type = size_t; 82 | 83 | using value_type = Item; 84 | using reference = value_type&; 85 | using const_reference = const value_type&; 86 | using pointer = value_type*; 87 | using const_pointer = const value_type*; 88 | 89 | using self_type = triv; 90 | 91 | bool empty() const { 92 | return seq.empty(); 93 | } 94 | 95 | size_type size() const { 96 | return seq.get_cached(); 97 | } 98 | 99 | value_type& front() { 100 | top_item_type& x = seq.front(); 101 | return x.value; 102 | } 103 | 104 | value_type& back() { 105 | top_item_type& x = seq.back(); 106 | return x.value; 107 | } 108 | 109 | void push_front(const value_type& v) { 110 | seq.push_front(meas_fct, new top_item_type(v)); 111 | } 112 | 113 | void push_back(const value_type& v) { 114 | seq.push_back(meas_fct, new top_item_type(v)); 115 | } 116 | 117 | value_type pop_front() { 118 | top_item_type x = seq.pop_front(); 119 | value_type v = x.value; 120 | delete x; 121 | return v; 122 | } 123 | 124 | value_type pop_back() { 125 | top_item_type x = seq.pop_back(); 126 | value_type v = x.value; 127 | delete x; 128 | return v; 129 | } 130 | 131 | void split(size_type n, self_type& other) { 132 | if (n == 0) 133 | return; 134 | size_type index = n - 1; 135 | size_type sz = size(); 136 | assert(index < sz); 137 | top_item_type* v; 138 | seq.split(index, v, other.seq); 139 | assert(size() == index); 140 | seq.push_back(meas_fct, v); 141 | } 142 | 143 | void concat(self_type& other) { 144 | seq.concat(other.seq); 145 | } 146 | 147 | template 148 | void for_each(const Body& f) const { 149 | seq.for_each([&] (top_item_type* v) { 150 | f(v->value); 151 | }); 152 | } 153 | 154 | }; 155 | 156 | /***********************************************************************/ 157 | 158 | } // end namespace 159 | } // end namespace 160 | } // end namespace 161 | } // end namespace 162 | 163 | #endif /*! _PASL_DATA_TRIVBOOTCHUNKEDSEQ_H_ */ -------------------------------------------------------------------------------- /examples/weighted_split.cpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * \author Umut A. Acar 3 | * \author Arthur Chargueraud 4 | * \author Mike Rainey 5 | * \date 2013-2018 6 | * \copyright 2014 Umut A. Acar, Arthur Chargueraud, Mike Rainey 7 | * 8 | * \brief Example use of the chunked sequence for weighted split 9 | * \file weighted_split.cpp 10 | * \example weighted_split.cpp 11 | * \ingroup chunkedseq 12 | * \ingroup cached_measurement 13 | * 14 | */ 15 | 16 | //! [weighted_split_example] 17 | #include 18 | #include 19 | 20 | #include "chunkedseq.hpp" 21 | 22 | namespace cachedmeasure = pasl::data::cachedmeasure; 23 | namespace chunkedseq = pasl::data::chunkedseq::bootstrapped; 24 | 25 | const int chunk_capacity = 512; 26 | 27 | int main(int argc, const char * argv[]) { 28 | 29 | using value_type = std::string; 30 | using weight_type = int; 31 | 32 | class my_weight_fct { 33 | public: 34 | // returns 1 if the length of the string is an even number; 0 otherwise 35 | weight_type operator()(const value_type& str) const { 36 | return (str.size() % 2 == 0) ? 1 : 0; 37 | } 38 | }; 39 | 40 | using my_cachedmeasure_type = 41 | cachedmeasure::weight; 42 | 43 | using my_weighted_deque_type = 44 | chunkedseq::deque; 45 | 46 | my_weighted_deque_type d = { "Let's", "divide", "this", "sequence", "of", 47 | "strings", "into", "two", "pieces" }; 48 | 49 | weight_type nb_even_length_strings = d.get_cached(); 50 | std::cout << "nb even-length strings: " << nb_even_length_strings << std::endl; 51 | 52 | my_weighted_deque_type f; 53 | 54 | d.split([=] (weight_type v) { return v >= nb_even_length_strings/2; }, f); 55 | 56 | std::cout << "d = " << std::endl; 57 | d.for_each([] (value_type& s) { std::cout << s << " "; }); 58 | std::cout << std::endl; 59 | std::cout << std::endl; 60 | 61 | std::cout << "f = " << std::endl; 62 | f.for_each([] (value_type& s) { std::cout << s << " "; }); 63 | std::cout << std::endl; 64 | 65 | return 0; 66 | 67 | } 68 | //! [weighted_split_example] 69 | -------------------------------------------------------------------------------- /include/algebra.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Definitions of a few algebras 8 | * \file algebra.hpp 9 | * 10 | */ 11 | 12 | #include "measure.hpp" 13 | 14 | #ifndef _PASL_DATA_ALGEBRA_H_ 15 | #define _PASL_DATA_ALGEBRA_H_ 16 | 17 | namespace pasl { 18 | namespace data { 19 | namespace algebra { 20 | 21 | /***********************************************************************/ 22 | 23 | /*---------------------------------------------------------------------*/ 24 | /*! 25 | * \class trivial 26 | * \ingroup algebras 27 | * \brief Trivial algebraic group whose sole element is a zero-byte structure 28 | * 29 | */ 30 | //! [trivial] 31 | class trivial { 32 | public: 33 | 34 | using value_type = struct { }; 35 | 36 | static constexpr bool has_inverse = true; 37 | 38 | static value_type identity() { 39 | return value_type(); 40 | } 41 | 42 | static value_type combine(value_type, value_type) { 43 | return identity(); 44 | } 45 | 46 | static value_type inverse(value_type) { 47 | return identity(); 48 | } 49 | 50 | }; 51 | //! [trivial] 52 | 53 | /*---------------------------------------------------------------------*/ 54 | /*! 55 | * \class int_group_under_addition_and_negation 56 | * \ingroup algebras 57 | * \brief Constructor for algebraic groups formed by integers along with sum and inverse operations 58 | * \tparam Int Type of the set of integers treated by the algebra 59 | */ 60 | //! [int_group_under_addition_and_negation] 61 | template 62 | class int_group_under_addition_and_negation { 63 | public: 64 | 65 | using value_type = Int; 66 | 67 | static constexpr bool has_inverse = true; 68 | 69 | static value_type identity() { 70 | return value_type(0); 71 | } 72 | 73 | static value_type combine(value_type x, value_type y) { 74 | return x + y; 75 | } 76 | 77 | static value_type inverse(value_type x) { 78 | return value_type(-1) * x; 79 | } 80 | 81 | }; 82 | //! [int_group_under_addition_and_negation] 83 | 84 | /*---------------------------------------------------------------------*/ 85 | /*! 86 | * \class combiner 87 | * \ingroup algebras 88 | * \brief Combiner of two algebras 89 | * 90 | * Combines two algebras to make a new algebra that pairs together 91 | * values of the two given algebras. The resulting algebra combines 92 | * together the operations of the given algebras to operate pointwise 93 | * on the values of the pairs. 94 | * 95 | * The resulting algebra has an inverse operator only if both of its 96 | * subalgebras has inverse operators and otherwise does not. 97 | * 98 | * \tparam Algebra1 an algebra 99 | * \tparam Algebra2 an algebra 100 | * 101 | */ 102 | //! [combiner] 103 | template 104 | class combiner { 105 | public: 106 | 107 | using algebra1_type = Algebra1; 108 | using algebra2_type = Algebra2; 109 | 110 | using value1_type = typename Algebra1::value_type; 111 | using value2_type = typename Algebra2::value_type; 112 | 113 | using value_type = measure::measured_pair; 114 | 115 | static constexpr bool has_inverse = 116 | algebra1_type::has_inverse 117 | && algebra2_type::has_inverse; 118 | 119 | static value_type identity() { 120 | return measure::make_measured_pair(algebra1_type::identity(), 121 | algebra2_type::identity()); 122 | } 123 | 124 | static value_type combine(value_type x, value_type y) { 125 | return measure::make_measured_pair(algebra1_type::combine(x.value1, y.value1), 126 | algebra2_type::combine(x.value2, y.value2)); 127 | } 128 | 129 | static value_type inverse(value_type x) { 130 | return measure::make_measured_pair(algebra1_type::inverse(x.value1), 131 | algebra2_type::inverse(x.value2)); 132 | } 133 | 134 | }; 135 | //! [combiner] 136 | 137 | /*! 138 | * \function subtract 139 | * \ingroup algebras 140 | * \brief Subtraction operator 141 | * \pre the algebra defines an inverse operator (i.e., `Algebra::has_inverse == true`) 142 | * \tparam Algebra an algebra 143 | * 144 | * Returns `combine(x, inverse(y))`. 145 | */ 146 | template 147 | typename Algebra::value_type subtract(typename Algebra::value_type x, 148 | typename Algebra::value_type y) { 149 | assert(Algebra::has_inverse); 150 | return combine(x, Algebra::inverse(y)); 151 | } 152 | 153 | /***********************************************************************/ 154 | 155 | } // end namespace 156 | } // end namespace 157 | } // end namespace 158 | 159 | #endif /*! _PASL_DATA_ALGEBRA_H_ */ 160 | -------------------------------------------------------------------------------- /include/annotation.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Defines an interface for attaching data to nodes in the 8 | * underlying tree structure of the chunked sequence 9 | * \file annotation.hpp 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | #ifndef _PASL_DATA_ANNOTATION_H_ 17 | #define _PASL_DATA_ANNOTATION_H_ 18 | 19 | namespace pasl { 20 | namespace data { 21 | namespace chunkedseq { 22 | namespace annotation { 23 | 24 | /***********************************************************************/ 25 | 26 | /*---------------------------------------------------------------------*/ 27 | /* Tagged values */ 28 | 29 | /** 30 | * \defgroup tagged Tagged values 31 | * @ingroup data_structures 32 | * @{ 33 | * 34 | * \brief A tagged value is a word which consists of a small integer 35 | * tag and a large integer value. 36 | * 37 | * The size in bits of the value is just large enough to contain a 38 | * (properly aligned) pointer. 39 | * 40 | * The operations typically use three types: 41 | * - The type of the tag, value pair is named `Tagged`. 42 | * - The type of the value is named `Value`. 43 | * - The tag has type `long`. 44 | * 45 | * \note Currently this module supports only 64-bit words. As such, 46 | * the tag is a 3 bit integer and the value a 61 bit integer. 47 | * 48 | */ 49 | 50 | //! Size in bits of the tag 51 | const long NUM_TAG_BITS = 3; 52 | //! Bit mask for the tag 53 | const long TAG_MASK = (1< 60 | static inline Tagged create(Value v, long bits) { 61 | assert(sizeof(Value) == sizeof(int64_t)); 62 | assert(sizeof(Tagged) == sizeof(int64_t)); 63 | assert(bits <= TAG_MASK); 64 | union enc { 65 | Value v; 66 | Tagged t; 67 | uint64_t bits; 68 | }; 69 | enc e; 70 | e.v = v; 71 | assert((e.bits & TAG_MASK) == 0l); 72 | e.bits |= (uint64_t)bits; 73 | return e.t; 74 | } 75 | 76 | /*! \brief Returns the value component of the pair */ 77 | template 78 | static inline Value extract_value(Tagged t) { 79 | assert(sizeof(Value) == sizeof(int64_t)); 80 | assert(sizeof(Tagged) == sizeof(int64_t)); 81 | union enc { 82 | Value v; 83 | Tagged t; 84 | uint64_t bits; 85 | }; 86 | enc e; 87 | e.t = t; 88 | e.bits &= ~ TAG_MASK; 89 | return e.v; 90 | } 91 | 92 | /*! \brief Returns the tag component of the pair */ 93 | template 94 | static inline long extract_tag(Tagged t) { 95 | assert(sizeof(Value) == sizeof(int64_t)); 96 | assert(sizeof(Tagged) == sizeof(int64_t)); 97 | union enc { 98 | Value v; 99 | Tagged t; 100 | uint64_t bits; 101 | }; 102 | enc e; 103 | e.t = t; 104 | e.bits &= TAG_MASK; 105 | return (long)e.bits; 106 | } 107 | 108 | /** 109 | * @} 110 | */ 111 | 112 | /*---------------------------------------------------------------------*/ 113 | /* Optional support for parent pointers */ 114 | 115 | using parent_pointer_tag = enum { 116 | PARENT_POINTER_BOOTSTRAP_INTERIOR_NODE=0, 117 | PARENT_POINTER_BOOTSTRAP_LAYER_NODE=1, 118 | PARENT_POINTER_CHUNK=2, 119 | PARENT_POINTER_UNINITIALIZED=3 120 | }; 121 | 122 | template 123 | class with_parent_pointer { 124 | public: 125 | 126 | using self_type = with_parent_pointer; 127 | 128 | private: 129 | 130 | mutable void* parent_ptr; 131 | mutable Measured prefix; 132 | mutable int depth; 133 | 134 | public: 135 | 136 | static constexpr bool enabled = true; 137 | 138 | with_parent_pointer() { 139 | set_pointer(nullptr, PARENT_POINTER_UNINITIALIZED); 140 | depth = -1; 141 | } 142 | 143 | template 144 | Pointer get_pointer() const { 145 | return extract_value(parent_ptr); 146 | } 147 | 148 | parent_pointer_tag get_tag() const { 149 | long t = extract_tag(parent_ptr); 150 | if (t == PARENT_POINTER_BOOTSTRAP_INTERIOR_NODE) 151 | return PARENT_POINTER_BOOTSTRAP_INTERIOR_NODE; 152 | else if (t == PARENT_POINTER_BOOTSTRAP_LAYER_NODE) 153 | return PARENT_POINTER_BOOTSTRAP_LAYER_NODE; 154 | else if (t == PARENT_POINTER_UNINITIALIZED) 155 | return PARENT_POINTER_UNINITIALIZED; 156 | else { 157 | assert(false); 158 | return PARENT_POINTER_UNINITIALIZED; 159 | } 160 | } 161 | 162 | int get_depth() const { 163 | return depth; 164 | } 165 | 166 | template 167 | Measured1 get_prefix() const { 168 | return prefix; 169 | } 170 | 171 | template 172 | void set_pointer(Pointer p, parent_pointer_tag t) const { 173 | parent_ptr = create(p, t); 174 | assert(get_tag() == t); 175 | } 176 | 177 | void set_depth(int d) const { 178 | depth = d; 179 | } 180 | 181 | template 182 | void set_prefix(Measured1 m) const { 183 | prefix = m; 184 | } 185 | 186 | void swap(self_type& other) { 187 | std::swap(parent_ptr, other.parent_ptr); 188 | std::swap(depth, other.depth); 189 | std::swap(prefix, other.prefix); 190 | } 191 | 192 | }; 193 | 194 | class without_parent_pointer { 195 | public: 196 | 197 | using self_type = without_parent_pointer; 198 | 199 | static constexpr bool enabled = false; 200 | 201 | template 202 | Pointer get_pointer() const { 203 | return nullptr; 204 | } 205 | 206 | parent_pointer_tag get_tag() const { 207 | return PARENT_POINTER_UNINITIALIZED; 208 | } 209 | 210 | int get_depth() const { 211 | return -1; 212 | } 213 | 214 | template 215 | Measured get_prefix() const { 216 | return Measured(); 217 | } 218 | 219 | template 220 | void set_pointer(Pointer, parent_pointer_tag) const { 221 | } 222 | 223 | void set_depth(int) const { 224 | 225 | } 226 | 227 | template 228 | void set_prefix(Measured) const { 229 | 230 | } 231 | 232 | void swap(self_type&) { 233 | 234 | } 235 | 236 | }; 237 | 238 | /*---------------------------------------------------------------------*/ 239 | /* Optional suppport for chains of inter-chunk pointers */ 240 | 241 | class with_chain { 242 | public: 243 | 244 | using self_type = with_chain; 245 | 246 | private: 247 | 248 | void* next; 249 | void* prev; 250 | 251 | public: 252 | 253 | static constexpr bool enabled = true; 254 | 255 | with_chain() 256 | : next(nullptr), prev(nullptr) { } 257 | 258 | template 259 | Pointer get_next() const { 260 | return (Pointer)next; 261 | } 262 | 263 | template 264 | Pointer get_prev() const { 265 | return (Pointer)prev; 266 | } 267 | 268 | template 269 | static void link(self_type& l1, self_type& l2, Pointer p1, Pointer p2) { 270 | l1.next = (void*)p2; 271 | l2.prev = (void*)p1; 272 | } 273 | 274 | template 275 | static void unlink(self_type& l1, self_type& l2, Pointer p1, Pointer p2) { 276 | assert(l1.get_next() == (void*)p2); 277 | assert((void*)p1 == l2.get_prev()); 278 | l1.next = nullptr; 279 | l2.prev = nullptr; 280 | } 281 | 282 | void swap(self_type& other) { 283 | std::swap(next, other.next); 284 | std::swap(prev, other.prev); 285 | } 286 | 287 | }; 288 | 289 | class without_chain { 290 | public: 291 | 292 | using self_type = without_chain; 293 | 294 | static constexpr bool enabled = false; 295 | 296 | template 297 | Pointer get_next() const { 298 | return nullptr; 299 | } 300 | 301 | template 302 | Pointer get_prev() const { 303 | return nullptr; 304 | } 305 | 306 | template 307 | static void link(self_type& l1, self_type& l2, Pointer p1, Pointer p2) { 308 | } 309 | 310 | template 311 | static void unlink(self_type& l1, self_type& l2, Pointer p1, Pointer p2) { 312 | } 313 | 314 | void swap(self_type& other) { 315 | } 316 | 317 | }; 318 | 319 | /*---------------------------------------------------------------------*/ 320 | /* Optional support for cached measurements */ 321 | 322 | class without_measured { 323 | public: 324 | 325 | using measured_type = struct { }; 326 | using self_type = without_measured; 327 | 328 | static constexpr bool enabled = false; 329 | 330 | template 331 | Measured get_cached() const { 332 | return Measured(); 333 | } 334 | 335 | template 336 | void set_cached(Measured m) const { 337 | 338 | } 339 | 340 | void swap(self_type& other) { 341 | 342 | } 343 | 344 | }; 345 | 346 | class std_swap { 347 | public: 348 | template 349 | static void swap(T& x, T& y) { 350 | std::swap(x, y); 351 | } 352 | }; 353 | 354 | template 355 | class with_measured { 356 | public: 357 | 358 | using measured_type = Measured; 359 | using self_type = with_measured; 360 | 361 | static constexpr bool enabled = true; 362 | 363 | mutable measured_type cached; 364 | 365 | template 366 | Measured1 get_cached() const { 367 | return cached; 368 | } 369 | 370 | template 371 | void set_cached(Measured1 m) const { 372 | cached = m; 373 | } 374 | 375 | void swap(self_type& other) { 376 | Swap_measured::swap(cached, other.cached); 377 | } 378 | 379 | }; 380 | 381 | /*---------------------------------------------------------------------*/ 382 | /* Annotation builder */ 383 | 384 | template < 385 | class Measured=without_measured, 386 | class Parent_pointer=without_parent_pointer, 387 | class Sibling_pointer=without_chain 388 | > 389 | class annotation_builder { 390 | public: 391 | 392 | using self_type = annotation_builder; 393 | using cached_prefix_type = Measured; 394 | using parent_pointer_type = Parent_pointer; 395 | 396 | static constexpr bool finger_search_enabled = Measured::enabled && Parent_pointer::enabled; 397 | 398 | Measured prefix; 399 | Parent_pointer parent; 400 | Sibling_pointer sibling; 401 | 402 | void swap(self_type& other) { 403 | prefix.swap(other.prefix); 404 | parent.swap(other.parent); 405 | sibling.swap(other.sibling); 406 | } 407 | 408 | }; 409 | 410 | /***********************************************************************/ 411 | 412 | } // end namespace 413 | } // end namespace 414 | } // end namespace 415 | } // end namespace 416 | 417 | #endif /*! _PASL_DATA_ANNOTATION_H_ */ 418 | -------------------------------------------------------------------------------- /include/cachedmeasure.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Definitions of a few cached-measurement policies 8 | * \file cachedmeasure.hpp 9 | * 10 | */ 11 | 12 | #include "algebra.hpp" 13 | 14 | #ifndef _PASL_DATA_CACHEDMEASURE_H_ 15 | #define _PASL_DATA_CACHEDMEASURE_H_ 16 | 17 | namespace pasl { 18 | namespace data { 19 | namespace cachedmeasure { 20 | 21 | /***********************************************************************/ 22 | 23 | /*---------------------------------------------------------------------*/ 24 | //! [trivial] 25 | template 26 | class trivial { 27 | public: 28 | 29 | using size_type = Size; 30 | using value_type = Item; 31 | using algebra_type = algebra::trivial; 32 | using measured_type = typename algebra_type::value_type; 33 | using measure_type = measure::trivial; 34 | 35 | static void swap(measured_type& x, measured_type& y) { 36 | // nothing to do 37 | } 38 | 39 | }; 40 | //! [trivial] 41 | 42 | /*---------------------------------------------------------------------*/ 43 | //! [size] 44 | template 45 | class size { 46 | public: 47 | 48 | using size_type = Size; 49 | using value_type = Item; 50 | using algebra_type = algebra::int_group_under_addition_and_negation; 51 | using measured_type = typename algebra_type::value_type; 52 | using measure_type = measure::uniform; 53 | 54 | static void swap(measured_type& x, measured_type& y) { 55 | std::swap(x, y); 56 | } 57 | 58 | }; 59 | //! [size] 60 | 61 | /*---------------------------------------------------------------------*/ 62 | //! [weight] 63 | template 64 | class weight { 65 | public: 66 | 67 | using size_type = Size; 68 | using value_type = Item; 69 | using algebra_type = algebra::int_group_under_addition_and_negation; 70 | using measured_type = typename algebra_type::value_type; // = Weight 71 | using measure_env_type = Measure_environment; 72 | using measure_type = measure::weight; 73 | 74 | static void swap(measured_type& x, measured_type& y) { 75 | std::swap(x, y); 76 | } 77 | 78 | }; 79 | //! [weight] 80 | 81 | /*---------------------------------------------------------------------*/ 82 | //! [combiner] 83 | template 84 | class combiner { 85 | public: 86 | 87 | using algebra1_type = typename Cache1::algebra_type; 88 | using algebra2_type = typename Cache2::algebra_type; 89 | using measure1_type = typename Cache1::measure_type; 90 | using measure2_type = typename Cache2::measure_type; 91 | 92 | using size_type = typename Cache1::size_type; 93 | using value_type = typename Cache1::value_type; 94 | using algebra_type = algebra::combiner; 95 | using measured_type = typename algebra_type::value_type; 96 | using measure_type = measure::combiner; 97 | 98 | static void swap(measured_type& x, measured_type& y) { 99 | Cache1::swap(x.value1, y.value1); 100 | Cache2::swap(x.value2, y.value2); 101 | } 102 | 103 | }; 104 | //! [combiner] 105 | 106 | /***********************************************************************/ 107 | 108 | } // end namespace 109 | } // end namespace 110 | } // end namespace 111 | 112 | #endif /*! _PASL_DATA_CACHEDMEASURE_H_ */ 113 | -------------------------------------------------------------------------------- /include/chunk.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Representation of a chunk 8 | * \file chunk.hpp 9 | * 10 | */ 11 | 12 | #include "itemsearch.hpp" 13 | #include "annotation.hpp" 14 | 15 | #ifndef _PASL_DATA_CHUNK_H_ 16 | #define _PASL_DATA_CHUNK_H_ 17 | 18 | namespace pasl { 19 | namespace data { 20 | namespace chunkedseq { 21 | 22 | /***********************************************************************/ 23 | 24 | /*---------------------------------------------------------------------*/ 25 | // Carrier for a deallocation function that calls "delete" on its argument 26 | 27 | class Pointer_deleter { 28 | public: 29 | static constexpr bool should_use = true; 30 | template 31 | static void dealloc(Item* x) { 32 | delete x; 33 | } 34 | }; 35 | 36 | class Dummy_pointer_deleter { // does nothing 37 | public: 38 | static constexpr bool should_use = false; 39 | template 40 | static void dealloc(Item x) { 41 | assert(false); 42 | } 43 | }; 44 | 45 | /*---------------------------------------------------------------------*/ 46 | // Carrier for a deep-copy function that calls the copy constructor on its argument 47 | 48 | class Pointer_deep_copier { 49 | public: 50 | static constexpr bool should_use = true; 51 | template 52 | static Item* copy(Item* x) { 53 | return new Item(*x); 54 | }; 55 | }; 56 | 57 | class Dummy_pointer_deep_copier { // does nothing 58 | public: 59 | static constexpr bool should_use = false; 60 | template 61 | static Item copy(Item x) { 62 | assert(false); 63 | return x; 64 | }; 65 | }; 66 | 67 | /*---------------------------------------------------------------------*/ 68 | /*! 69 | * \class chunk 70 | * \brief Fixed-capacity array along with cached measurement of array contents 71 | * \tparam Fixed_capacity_queue type of the fixed-capacity array 72 | * \tparam Cached_measure type of the policy used to maintain the cached measurement 73 | * \tprarm Annotation type of an annotation object that a client might want to attach, 74 | * e.g., parent/sibling pointer 75 | * \tparam Pointer_deleter1 type of the policy used to manage deallocation 76 | * of (pointer-value) items 77 | * \tparam Pointer_deep_copier1 type of the policy used to manage copying 78 | * of (pointer-value) items 79 | * 80 | * We assume that each chunk consists of one or two segments. Two 81 | * segments indicates wraparound in a ringbuffer. In the future we 82 | * might consider supporting unbounded segments. 83 | */ 84 | template < 85 | class Fixed_capacity_queue, 86 | class Cached_measure, 87 | class Annotation=annotation::annotation_builder<>, 88 | class Pointer_deleter1=Dummy_pointer_deleter, 89 | class Pointer_deep_copier1=Dummy_pointer_deep_copier, 90 | class Size_access=itemsearch::no_size_access 91 | > 92 | class chunk { 93 | public: 94 | 95 | /*---------------------------------------------------------------------*/ 96 | /** @name Item-specific types 97 | */ 98 | ///@{ 99 | using queue_type = Fixed_capacity_queue; 100 | using value_type = typename queue_type::value_type; 101 | using reference = value_type&; 102 | using const_reference = const value_type&; 103 | using pointer = value_type*; 104 | using const_pointer = const value_type*; 105 | using segment_type = typename queue_type::segment_type; 106 | using const_segment_type = typename queue_type::const_segment_type; 107 | ///@} 108 | 109 | /*---------------------------------------------------------------------*/ 110 | /** @name Cached-measurement-specific types 111 | */ 112 | ///@{ 113 | using cache_type = Cached_measure; 114 | using measured_type = typename cache_type::measured_type; 115 | using algebra_type = typename cache_type::algebra_type; 116 | using measure_type = typename cache_type::measure_type; 117 | ///@} 118 | 119 | /*---------------------------------------------------------------------*/ 120 | /** @name Container-configuration types 121 | */ 122 | ///@{ 123 | using size_type = typename cache_type::size_type; 124 | using annotation_type = Annotation; 125 | using self_type = chunk; 126 | ///@} 127 | 128 | //! capacity in number of items 129 | static constexpr int capacity = queue_type::capacity; 130 | 131 | //! queue structure to contain the items of the chunk 132 | queue_type items; 133 | //! cached measurement of the items contained in the chunk 134 | measured_type cached; 135 | //! annotation value to be attached to the chunk 136 | annotation_type annotation; 137 | 138 | using search_type = itemsearch::search_in_chunk; 139 | 140 | private: 141 | 142 | /* Note: 143 | * Our combine operator is not necessarily commutative. 144 | * as such, we need to be careful to get the order of the 145 | * operands right when we increment on the front and back. 146 | */ 147 | 148 | inline void incr_front(const measured_type& m) { 149 | cached = algebra_type::combine(m, cached); 150 | } 151 | 152 | inline void incr_back(const measured_type& m) { 153 | cached = algebra_type::combine(cached, m); 154 | } 155 | 156 | inline void decr_front(const measured_type& m) { 157 | incr_front(algebra_type::inverse(m)); 158 | } 159 | 160 | inline void decr_back(const measured_type& m) { 161 | incr_back(algebra_type::inverse(m)); 162 | } 163 | 164 | inline measured_type measure_range(const measure_type& meas, size_type lo, size_type hi) const { 165 | size_type nb = hi - lo; 166 | size_type sz = size(); 167 | assert(nb <= sz); 168 | measured_type res = algebra_type::identity(); 169 | items.for_each_segment(int(lo), int(hi), [&] (const_pointer lo, const_pointer hi) { 170 | res = algebra_type::combine(res, meas(lo, hi)); 171 | }); 172 | return res; 173 | } 174 | 175 | inline measured_type measure(const measure_type& meas) const { 176 | return measure_range(meas, 0, size()); 177 | } 178 | 179 | //! \todo change interface of incr/decr frontn/backn to take nb items instead of offset 180 | 181 | /* increments the cached measurement by the combined measurements 182 | * of the items at positions [0, hi] 183 | */ 184 | inline void incr_frontn(const measure_type& meas, size_type hi) { 185 | incr_front(measure_range(meas, 0, hi)); 186 | } 187 | 188 | /* increments the cached measurement by the combined measurements 189 | * of the items at positions [lo, size()] 190 | */ 191 | inline void incr_backn(const measure_type& meas, size_type lo) { 192 | incr_back(measure_range(meas, lo, size())); 193 | } 194 | 195 | inline void decr_frontn(const measure_type& meas, size_type hi) { 196 | decr_front(measure_range(meas, 0, hi)); 197 | } 198 | 199 | inline void decr_backn(const measure_type& meas, size_type lo) { 200 | decr_back(measure_range(meas, lo, size())); 201 | } 202 | 203 | public: 204 | 205 | /*---------------------------------------------------------------------*/ 206 | /** @name Constructors and destructors 207 | */ 208 | ///@{ 209 | chunk() { 210 | cached = algebra_type::identity(); 211 | } 212 | 213 | chunk(const self_type& other) 214 | : cached(other.cached), items(other.items), annotation(other.annotation) { 215 | if (Pointer_deep_copier1::should_use) 216 | for_each([&] (value_type& v) { 217 | v = Pointer_deep_copier1::copy(v); 218 | }); 219 | } 220 | 221 | ~chunk() { 222 | if (Pointer_deleter1::should_use) 223 | for_each([&] (value_type& v) { 224 | Pointer_deleter1::dealloc(v); 225 | }); 226 | } 227 | ///@} 228 | 229 | /*---------------------------------------------------------------------*/ 230 | /** @name Capacity 231 | */ 232 | ///@{ 233 | bool full() const { 234 | return items.full(); 235 | } 236 | 237 | bool empty() const { 238 | return items.empty(); 239 | } 240 | 241 | bool partial() const { 242 | return items.partial(); 243 | } 244 | 245 | size_type size() const { 246 | return items.size(); 247 | } 248 | ///@} 249 | 250 | /*---------------------------------------------------------------------*/ 251 | /** @name Cached measurement 252 | */ 253 | ///@{ 254 | measured_type get_cached() const { 255 | return cached; 256 | } 257 | ///@} 258 | 259 | /*---------------------------------------------------------------------*/ 260 | /** @name Item access 261 | */ 262 | ///@{ 263 | value_type& front() const { 264 | return items.front(); 265 | } 266 | 267 | value_type& back() const { 268 | return items.back(); 269 | } 270 | 271 | void frontn(value_type* xs, size_type nb) { 272 | items.frontn(xs, (int)nb); 273 | } 274 | 275 | void backn(value_type* xs, size_type nb) { 276 | items.backn(xs, (int)nb); 277 | } 278 | 279 | value_type& operator[](size_type ix) const { 280 | return items[ix]; 281 | } 282 | 283 | template 284 | void for_each(const Body& body) const { 285 | items.for_each(body); 286 | } 287 | 288 | template 289 | void for_each_segment(const Body& body) const { 290 | for_each_segment(size_type(0), size(), body); 291 | } 292 | 293 | // lo inclusive; hi exclusive 294 | template 295 | void for_each_segment(size_type lo, size_type hi, const Body& body) const { 296 | items.for_each_segment(int(lo), int(hi), body); 297 | } 298 | 299 | segment_type segment_by_index(size_type i) const { 300 | return items.segment_by_index(int(i)); 301 | } 302 | 303 | const_segment_type csegment_by_index(size_type i) const { 304 | return items.csegment_by_index(int(i)); 305 | } 306 | 307 | size_type index_of_pointer(const value_type* p) const { 308 | return items.index_of_pointer(p); 309 | } 310 | ///@} 311 | 312 | /*---------------------------------------------------------------------*/ 313 | /** @name Modifiers 314 | */ 315 | ///@{ 316 | void push_front(const measure_type& meas, const value_type& x) { 317 | items.push_front(x); 318 | incr_front(meas(x)); 319 | } 320 | 321 | void push_back(const measure_type& meas, const value_type& x) { 322 | items.push_back(x); 323 | incr_back(meas(x)); 324 | } 325 | 326 | value_type pop_front(const measure_type& meas) { 327 | value_type v = front(); 328 | if (algebra_type::has_inverse) 329 | decr_front(meas(v)); 330 | items.pop_front(); 331 | if (! algebra_type::has_inverse) 332 | reset_cache(meas); 333 | return v; 334 | } 335 | 336 | value_type pop_back(const measure_type& meas) { 337 | value_type v = back(); 338 | if (algebra_type::has_inverse) 339 | decr_back(meas(v)); 340 | items.pop_back(); 341 | if (! algebra_type::has_inverse) 342 | reset_cache(meas); 343 | return v; 344 | } 345 | 346 | /* TODO: would this code be more efficient when has_inverse is true? 347 | value_type pop_front(const measure_type& meas) { 348 | value_type v = items.pop_front(); 349 | if (algebra_type::has_inverse) 350 | decr_front(meas(v)); 351 | if (! algebra_type::has_inverse) 352 | reset_cache(meas); 353 | return v; 354 | } 355 | 356 | value_type pop_back(const measure_type& meas) { 357 | value_type v = items.pop_back(); 358 | if (algebra_type::has_inverse) 359 | decr_back(meas(v)); 360 | if (! algebra_type::has_inverse) 361 | reset_cache(meas); 362 | return v; 363 | } 364 | */ 365 | 366 | void pushn_front(const measure_type& meas, const value_type* xs, size_type nb) { 367 | items.pushn_front(xs, (int)nb); 368 | incr_frontn(meas, nb); 369 | } 370 | 371 | void pushn_back(const measure_type& meas, const value_type* xs, size_type nb) { 372 | size_type nb_before = size(); 373 | items.pushn_back(xs, (int)nb); 374 | incr_backn(meas, int(nb_before)); 375 | } 376 | 377 | template 378 | void pushn_back(const measure_type& meas, const Body& body, size_type nb) { 379 | size_type nb_before = size(); 380 | items.pushn_back(body, (int)nb); 381 | incr_backn(meas, int(nb_before)); 382 | } 383 | 384 | void popn_front(const measure_type& meas, size_type nb) { 385 | if (algebra_type::has_inverse) 386 | decr_frontn(meas, nb); 387 | items.popn_front(int(nb)); 388 | if (! algebra_type::has_inverse) 389 | reset_cache(meas); 390 | } 391 | 392 | void popn_back(const measure_type& meas, size_type nb) { 393 | if (algebra_type::has_inverse) { 394 | size_type nb_before = size() - nb; 395 | decr_backn(meas, nb_before); 396 | } 397 | items.popn_back((int)nb); 398 | if (! algebra_type::has_inverse) 399 | reset_cache(meas); 400 | } 401 | 402 | void popn_front(const measure_type& meas, value_type* xs, size_type nb) { 403 | check_cached(meas); 404 | if (algebra_type::has_inverse) 405 | decr_frontn(meas, nb); 406 | items.popn_front(xs, (int)nb); 407 | if (! algebra_type::has_inverse) 408 | reset_cache(meas); 409 | check_cached(meas); 410 | } 411 | 412 | void popn_back(const measure_type& meas, value_type* xs, size_type nb) { 413 | if (algebra_type::has_inverse) { 414 | size_type nb_before = size() - nb; 415 | decr_backn(meas, nb_before); 416 | } 417 | items.popn_back(xs, (int)nb); 418 | if (! algebra_type::has_inverse) 419 | reset_cache(meas); 420 | } 421 | 422 | template 423 | void popn_back(const measure_type& meas, const Consumer& cons, size_type nb) { 424 | size_type sz = size(); 425 | assert(nb <= sz); 426 | if (should_consume && sz > 0 && nb > 0) { 427 | size_type i = sz - nb; 428 | segment_type seg = segment_by_index(i); 429 | size_type sz_seg = seg.end - seg.middle; 430 | if (sz_seg == nb) { 431 | cons(seg.middle, seg.middle + nb); 432 | } else { // handle wraparound 433 | segment_type seg2 = segment_by_index(i + sz_seg); 434 | cons(seg2.middle, seg2.middle + (nb - sz_seg)); 435 | cons(seg.middle, seg.middle + sz_seg); 436 | } 437 | } 438 | popn_back(meas, nb); 439 | } 440 | 441 | template 442 | void popn_front(const measure_type& meas, const Consumer& cons, size_type nb) { 443 | size_type sz = size(); 444 | assert(nb <= sz); 445 | if (should_consume && sz > 0 && nb > 0) { 446 | size_type i = nb - 1; 447 | segment_type seg = segment_by_index(i); 448 | size_type sz_seg = seg.middle - seg.begin + 1; 449 | if (sz_seg == nb) { 450 | cons(seg.begin, seg.middle + 1); 451 | } else { // handle wraparound 452 | segment_type seg2 = segment_by_index(0); 453 | cons(seg2.begin, seg2.end); 454 | cons(seg.begin, seg.middle + 1); 455 | } 456 | } 457 | popn_front(meas, nb); 458 | } 459 | 460 | void transfer_from_back_to_front(const measure_type& meas, chunk& target, size_type nb) { 461 | size_type sz = size(); 462 | assert(sz >= nb); 463 | measured_type delta = measure_range(meas, sz - nb, sz); 464 | if (algebra_type::has_inverse) 465 | decr_back(delta); 466 | items.transfer_from_back_to_front(target.items, (int)nb); 467 | if (! algebra_type::has_inverse) 468 | reset_cache(meas); 469 | target.incr_front(delta); 470 | } 471 | 472 | void transfer_from_front_to_back(const measure_type& meas, chunk& target, size_type nb) { 473 | measured_type delta = measure_range(meas, size_type(0), nb); 474 | if (algebra_type::has_inverse) 475 | decr_front(delta); 476 | items.transfer_from_front_to_back(target.items, (int)nb); 477 | if (! algebra_type::has_inverse) 478 | reset_cache(meas); 479 | target.incr_back(delta); 480 | } 481 | 482 | /* 3-way split: place in `x` the first item that reaches the target measure, 483 | * if there is such an item. 484 | * 485 | * write in `found` whether or not there is such an item. 486 | */ 487 | template 488 | typename Search::measured_type split(const measure_type& meas, 489 | const Pred& p, 490 | const Search& search, 491 | const Search_measure& search_meas, 492 | typename Search::measured_type prefix, 493 | bool& found, 494 | value_type& x, 495 | self_type& other) { 496 | auto res = search(*this, search_meas, prefix, p); 497 | size_type pos = res.position; // one-based index pointing at the target item 498 | prefix = res.prefix; 499 | size_type sz = size(); 500 | assert(sz > 0); 501 | assert(pos > 0); 502 | found = pos < sz+1; 503 | if (pos == 1) { 504 | x = pop_front(meas); 505 | swap(other); 506 | return prefix; 507 | } 508 | if (pos == sz) { 509 | x = pop_back(meas); 510 | return prefix; 511 | } 512 | transfer_from_back_to_front(meas, other, sz - pos); 513 | x = pop_back(meas); 514 | return prefix; 515 | } 516 | 517 | /* same as above but requires that there is an item in the chunk that reaches 518 | * the target measure 519 | */ 520 | template 521 | typename Search::measured_type split(const measure_type& meas, 522 | const Pred& p, 523 | const Search& search, 524 | const Search_measure& search_meas, 525 | typename Search::measured_type prefix, 526 | value_type& x, 527 | self_type& other) { 528 | bool found; 529 | prefix = split(meas, p, search, search_meas, prefix, found, x, other); 530 | assert(found); 531 | return prefix; 532 | } 533 | 534 | // 2-way split: based on a 3-way split ==> requires a predicate valid for a 3-way split 535 | template 536 | typename Search::measured_type split(const measure_type& meas, 537 | const Pred& p, 538 | const Search& search, 539 | const Search_measure& search_meas, 540 | typename Search::measured_type prefix, 541 | self_type& other) { 542 | value_type x; 543 | prefix = split(meas, p, search, search_meas, prefix, x, other); 544 | other.push_front(meas, x); 545 | return prefix; 546 | } 547 | 548 | template 549 | measured_type split(const measure_type& meas, 550 | const Pred& p, 551 | measured_type prefix, 552 | value_type& x, 553 | self_type& other) { 554 | search_type search; 555 | return split(meas, p, search, meas, prefix, x, other); 556 | } 557 | 558 | template 559 | measured_type split(const measure_type& meas, 560 | const Pred& p, 561 | measured_type prefix, 562 | self_type& other) { 563 | search_type search; 564 | return split(meas, p, search, meas, prefix, other); 565 | } 566 | 567 | void concat(const measure_type& meas, self_type& other) { 568 | other.transfer_from_front_to_back(meas, *this, other.size()); 569 | } 570 | 571 | void clear() { 572 | items.popn_back(int(size())); 573 | cached = algebra_type::identity(); 574 | } 575 | 576 | void swap(self_type& other) { 577 | items.swap(other.items); 578 | cache_type::swap(cached, other.cached); 579 | annotation.swap(other.annotation); 580 | } 581 | 582 | void reset_cache(const measure_type& meas) { 583 | cached = measure(meas); 584 | } 585 | ///@} 586 | 587 | void check_cached(const measure_type& meas) const { 588 | #ifdef DEBUG_CHUNK 589 | if (Size_access::enable_index_optimization) 590 | assert(Size_access::csize(measure(meas)) == Size_access::csize(cached)); 591 | #endif 592 | } 593 | 594 | }; 595 | 596 | /***********************************************************************/ 597 | 598 | } // end namespace 599 | } // end namespace 600 | } // end namespace 601 | 602 | #endif /*! _PASL_DATA_CHUNK_H_ */ 603 | -------------------------------------------------------------------------------- /include/chunkedseq.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Chunked-sequence functor 8 | * \file chunkedseq.hpp 9 | * 10 | */ 11 | 12 | #include 13 | 14 | #include "fixedcapacity.hpp" 15 | #include "chunk.hpp" 16 | #include "cachedmeasure.hpp" 17 | #include "chunkedseqbase.hpp" 18 | #include "bootchunkedseq.hpp" 19 | #include "ftree.hpp" 20 | 21 | #ifndef _PASL_DATA_CHUNKEDSEQ_H_ 22 | #define _PASL_DATA_CHUNKEDSEQ_H_ 23 | 24 | namespace pasl { 25 | namespace data { 26 | namespace chunkedseq { 27 | 28 | /***********************************************************************/ 29 | 30 | /*---------------------------------------------------------------------*/ 31 | /* Place to put configuration classes for defining various 32 | * instantiations of the chunked-sequence functor 33 | */ 34 | 35 | template < 36 | class Item, 37 | int Chunk_capacity = 512, 38 | class Client_cache = cachedmeasure::trivial, 39 | template < 40 | class Chunk_item, 41 | int Capacity, 42 | class Item_alloc 43 | > 44 | class Chunk_struct = fixedcapacity::heap_allocated::ringbuffer_ptr, 45 | template < 46 | class Top_item_base, 47 | int ___Chunk_capacity, 48 | class ___Cached_measure, 49 | class Top_item_deleter, 50 | class Top_item_copier, 51 | template < 52 | class ___Item, 53 | int ___Capacity, 54 | class ___Item_alloc 55 | > 56 | class ___Chunk_struct, 57 | class Size_access 58 | > 59 | class Middle_sequence = bootchunkedseq::cdeque, 60 | class Item_alloc = std::allocator 61 | > 62 | class basic_deque_configuration { 63 | public: 64 | 65 | using size_type = typename Client_cache::size_type; 66 | using difference_type = ptrdiff_t; // later: check if this is ok 67 | 68 | using value_type = Item; 69 | using segment_type = segment; 70 | using const_segment_type = segment; 71 | 72 | static constexpr size_type chunk_capacity = size_type(Chunk_capacity); 73 | 74 | using item_allocator_type = Item_alloc; 75 | 76 | using item_queue_type = Chunk_struct; 77 | 78 | using client_algebra_type = typename Client_cache::algebra_type; 79 | using size_algebra_type = algebra::int_group_under_addition_and_negation; 80 | using middle_algebra_type = algebra::combiner; 81 | using middle_measured_type = typename middle_algebra_type::value_type; 82 | 83 | using chunk_cache_type = Client_cache; 84 | using chunk_measured_type = typename chunk_cache_type::measured_type; 85 | #ifdef DISABLE_RANDOM_ACCESS_ITERATOR 86 | using cached_prefix_type = annotation::without_measured; 87 | #else 88 | using cached_prefix_type = annotation::with_measured; 89 | #endif 90 | //! \todo fix bug in finger search that is causing iterator-based traversal to fail unit test in mode -generate_by_insert 1 91 | //! \todo once finger search bug is fixed, enable finger search by default 92 | #ifndef ENABLE_FINGER_SEARCH 93 | using parent_pointer_type = annotation::without_parent_pointer; 94 | #else 95 | using parent_pointer_type = annotation::with_parent_pointer; 96 | #endif 97 | using annotation_type = annotation::annotation_builder; 98 | using chunk_type = chunk; 99 | 100 | class middle_cache_type { 101 | public: 102 | 103 | using size_type = typename Client_cache::size_type; 104 | using value_type = const chunk_type*; 105 | using algebra_type = middle_algebra_type; 106 | using measured_type = typename algebra_type::value_type; 107 | 108 | class measure_type { 109 | public: 110 | 111 | using client_measure_type = typename Client_cache::measure_type; 112 | using client_value_type = typename chunk_type::value_type; 113 | 114 | private: 115 | 116 | client_measure_type client_meas; 117 | 118 | public: 119 | 120 | measure_type() { } 121 | 122 | measure_type(const client_measure_type& client_meas) 123 | : client_meas(client_meas) { } 124 | 125 | measured_type operator()(const client_value_type& v) const { 126 | measured_type m = algebra_type::identity(); 127 | m.value1 = size_type(1); 128 | m.value2 = client_meas(v); 129 | return m; 130 | } 131 | 132 | measured_type operator()(const client_value_type* lo, const client_value_type* hi) const { 133 | measured_type m = algebra_type::identity(); 134 | for (auto p = lo; p < hi; p++) 135 | m = algebra_type::combine(m, operator()(*p)); 136 | return m; 137 | } 138 | 139 | measured_type operator()(value_type p) const { 140 | measured_type m = algebra_type::identity(); 141 | m.value1 = p->size(); 142 | m.value2 = p->get_cached(); 143 | return m; 144 | } 145 | 146 | measured_type operator()(const value_type* lo, const value_type* hi) const { 147 | measured_type m = algebra_type::identity(); 148 | for (auto p = lo; p < hi; p++) 149 | m = algebra_type::combine(m, operator()(*p)); 150 | return m; 151 | } 152 | 153 | client_measure_type get_client_measure() const { 154 | return client_meas; 155 | } 156 | 157 | void set_client_measure(client_measure_type client_meas) { 158 | this->client_meas = client_meas; 159 | } 160 | 161 | }; 162 | 163 | static void swap(measured_type& x, measured_type& y) { 164 | std::swap(x.value1, y.value1); 165 | std::swap(x.value2, y.value2); 166 | } 167 | 168 | }; 169 | 170 | using middle_measure_type = typename middle_cache_type::measure_type; 171 | 172 | class size_access { 173 | public: 174 | using client_measured_type = chunk_measured_type; 175 | 176 | static constexpr bool enable_index_optimization = true; 177 | 178 | static size_type& size(middle_measured_type& m) { 179 | return m.value1; 180 | } 181 | static size_type csize(middle_measured_type m) { 182 | return m.value1; 183 | } 184 | static client_measured_type& client(middle_measured_type& m) { 185 | return m.value2; 186 | } 187 | static client_measured_type cclient(middle_measured_type m) { 188 | return m.value2; 189 | } 190 | }; 191 | 192 | #ifdef DEBUG_MIDDLE_SEQUENCE 193 | // use chunk as middle sequence; for the purpose of testing the chunkedseq functor in isolation. 194 | static constexpr int middle_capacity = 1<<23; 195 | using chunk_pointer_queue_type = fixedcapacity::heap_allocated::ringbuffer_ptr; 196 | using middle_annotation_type = annotation::annotation_builder<>; 197 | using middle_type = chunk; 199 | #else 200 | static constexpr int middle_chunk_capacity = 32; // 32 64 128; 201 | using middle_type = Middle_sequence; 203 | #endif 204 | 205 | using chunk_search_type = itemsearch::search_in_chunk; 206 | 207 | }; 208 | 209 | /*---------------------------------------------------------------------*/ 210 | /* Instantiations for the bootstrapped chunked sequence */ 211 | 212 | namespace bootstrapped { 213 | 214 | // Application of chunked deque to a configuration 215 | 216 | template < 217 | class Item, 218 | int Chunk_capacity=512, 219 | class Cache = cachedmeasure::trivial, 220 | template < 221 | class Chunk_item, 222 | int Capacity, 223 | class Chunk_item_alloc = std::allocator 224 | > 225 | class Chunk_struct = fixedcapacity::heap_allocated::ringbuffer_ptrx, 226 | class Item_alloc = std::allocator 227 | > 228 | using deque = chunkedseqbase>; 229 | 230 | // Application of chunked stack to a configuration 231 | 232 | template < 233 | class Item, 234 | int Chunk_capacity = 512, 235 | class Cache = cachedmeasure::trivial, 236 | class Item_alloc = std::allocator 237 | > 238 | using stack = deque; 239 | 240 | } // end namespace bootstrapped 241 | 242 | /*---------------------------------------------------------------------*/ 243 | /* Instantiations for the finger tree */ 244 | 245 | namespace ftree { 246 | 247 | // Application of a chunked finger tree to a configuration 248 | 249 | template < 250 | class Item, 251 | int Chunk_capacity = 512, 252 | class Cache = cachedmeasure::trivial, 253 | template < 254 | class Chunk_item, 255 | int Capacity, 256 | class Chunk_item_alloc = std::allocator 257 | > 258 | class Chunk_struct = fixedcapacity::heap_allocated::ringbuffer_ptrx, 259 | class Item_alloc = std::allocator 260 | > 261 | using deque = chunkedseqbase>; 262 | 263 | 264 | // Application of chunked finger tree to a configuration 265 | 266 | template < 267 | class Item, 268 | int Chunk_capacity = 512, 269 | class Cache = cachedmeasure::trivial, 270 | class Item_alloc = std::allocator 271 | > 272 | using stack = deque; 273 | 274 | } // end namespace ftree 275 | 276 | /***********************************************************************/ 277 | 278 | } // end namespace 279 | } // end namespace 280 | } // end namespace 281 | 282 | #endif /*! _PASL_DATA_CHUNKEDSEQ_H_ */ 283 | -------------------------------------------------------------------------------- /include/chunkedseqextras.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Extra container operations to be shared by chunked structures 8 | * \file chunkedseqextras.hpp 9 | * 10 | */ 11 | 12 | #ifndef _PASL_DATA_CHUNKEDSEQEXTRAS_H_ 13 | #define _PASL_DATA_CHUNKEDSEQEXTRAS_H_ 14 | 15 | namespace pasl { 16 | namespace data { 17 | namespace chunkedseq { 18 | namespace extras { 19 | 20 | /***********************************************************************/ 21 | 22 | /*---------------------------------------------------------------------*/ 23 | /* Various special-purpose forms of the split operation */ 24 | 25 | template 26 | void split_by_index(Container& c, size_type i, Container& other) { 27 | using measured_type = typename Container::middle_measured_type; 28 | using algebra_type = typename Container::middle_algebra_type; 29 | using size_access = typename Container::size_access; 30 | using predicate_type = itemsearch::less_than_by_position; 31 | c.check(); other.check(); 32 | size_type size_orig = c.size(); 33 | assert(i >= 0); 34 | assert(i <= size_orig); 35 | if (size_orig == 0) 36 | return; 37 | if (i == size_orig) 38 | return; 39 | if (i == 0) { 40 | c.swap(other); 41 | return; 42 | } 43 | predicate_type p(i); 44 | measured_type prefix = algebra_type::identity(); 45 | prefix = c.split_aux(p, prefix, other); 46 | c.check(); other.check(); 47 | size_type size_cur = c.size(); 48 | size_type size_other = other.size(); 49 | assert(size_other + size_cur == size_orig); 50 | assert(size_cur == i); 51 | assert(size_other + i == size_orig); 52 | assert(size_access::csize(prefix) == i); 53 | } 54 | 55 | template 56 | void split_by_iterator(Container& c, iterator position, Container& other) { 57 | using size_type = typename Container::size_type; 58 | if (position == c.end()) 59 | return; 60 | size_type n = position.size() - 1; 61 | c.split(n, other); 62 | } 63 | 64 | template 65 | void split_approximate(Container& c, Container& other) { 66 | using size_type = typename Container::size_type; 67 | assert(c.size() > 1); 68 | size_type mid = c.size() / 2; 69 | c.split(mid, other); 70 | } 71 | 72 | /*---------------------------------------------------------------------*/ 73 | /* Insert and erase */ 74 | 75 | template 76 | iterator insert(Container& c, iterator position, const value_type& val) { 77 | using self_type = Container; 78 | using size_type = typename Container::size_type; 79 | c.check(); 80 | size_type n = position.size() - 1; 81 | self_type tmp; 82 | c.split(position, tmp); 83 | c.push_back(val); 84 | c.concat(tmp); 85 | c.check(); 86 | return c.begin() + n; 87 | } 88 | 89 | template 90 | iterator erase(Container& c, iterator first, iterator last) { 91 | using self_type = Container; 92 | using size_type = typename Container::size_type; 93 | if (first == last) 94 | return first; 95 | size_type sz_orig = c.size(); 96 | self_type items_to_erase; 97 | size_type sz_first = first.size(); 98 | size_type sz_last = last.size(); 99 | size_type nb_to_erase = sz_last - sz_first; 100 | c.split(first, items_to_erase); 101 | self_type tmp; 102 | items_to_erase.split(nb_to_erase, tmp); 103 | items_to_erase.swap(tmp); 104 | c.concat(items_to_erase); 105 | assert(c.size() + nb_to_erase == sz_orig); 106 | return c.begin() + sz_first; 107 | } 108 | 109 | /*---------------------------------------------------------------------*/ 110 | /* For each loops */ 111 | 112 | template 113 | void for_each_segment(iterator begin, iterator end, const Body& f) { 114 | using segment_type = typename iterator::segment_type; 115 | if (begin >= end) 116 | return; 117 | segment_type seg_end = end.get_segment(); 118 | for (iterator i = begin; i != end; ) { 119 | segment_type seg = i.get_segment(); 120 | if (seg.begin == seg_end.begin) 121 | seg.end = seg_end.middle; 122 | f(seg.middle, seg.end); 123 | i += seg.end - seg.middle; 124 | } 125 | } 126 | 127 | template 128 | void for_each(iterator beg, iterator end, const Body& f) { 129 | using value_type = typename iterator::value_type; 130 | for_each_segment(beg, end, [&] (value_type* lo, value_type* hi) { 131 | for (value_type* p = lo; p < hi; p++) 132 | f(*p); 133 | }); 134 | } 135 | 136 | /*---------------------------------------------------------------------*/ 137 | /* Streaming operations */ 138 | 139 | template 140 | void stream_backn(const Container& c, const Consumer& cons, size_type nb) { 141 | using const_pointer = typename Container::const_pointer; 142 | assert(c.size() >= nb); 143 | size_type nb_before_target = c.size() - nb; 144 | c.for_each_segment(c.begin() + nb_before_target, c.end(), [&] (const_pointer lo, const_pointer hi) { 145 | size_type nb_items_to_copy = size_type(hi - lo); 146 | cons(lo, nb_items_to_copy); 147 | }); 148 | } 149 | 150 | template 151 | void stream_frontn(const Container& c, const Consumer& cons, size_type nb) { 152 | using const_pointer = typename Container::const_pointer; 153 | assert(c.size() >= nb); 154 | c.for_each_segment(c.begin(), c.begin() + nb, [&] (const_pointer lo, const_pointer hi) { 155 | size_type nb = size_type(hi - lo); 156 | cons(lo, nb); 157 | }); 158 | } 159 | 160 | template 161 | void backn(const Container& c, value_type* dst, size_type nb) { 162 | using const_pointer = const value_type*; 163 | using allocator_type = typename Container::allocator_type; 164 | value_type* p = dst; 165 | auto cons = [&] (const_pointer lo, size_type nb) { 166 | fixedcapacity::base::copy(p, lo, nb); 167 | p += nb; 168 | }; 169 | c.stream_backn(cons, nb); 170 | } 171 | 172 | template 173 | void frontn(const Container& c, value_type* dst, size_type nb) { 174 | using const_pointer = const value_type*; 175 | using allocator_type = typename Container::allocator_type; 176 | value_type* p = dst; 177 | auto cons = [&] (const_pointer lo, size_type nb) { 178 | fixedcapacity::base::copy(p, lo, nb); 179 | p += nb; 180 | }; 181 | c.stream_frontn(cons, nb); 182 | } 183 | 184 | template 185 | void pushn_back(Container& c, const_pointer src, size_type nb) { 186 | auto prod = [src] (size_type i, size_type nb) { 187 | const_pointer lo = src + i; 188 | const_pointer hi = lo + nb; 189 | return std::make_pair(lo, hi); 190 | }; 191 | c.stream_pushn_back(prod, nb); 192 | } 193 | 194 | template 195 | void pushn_front(Container& c, const_pointer src, size_type nb) { 196 | auto prod = [src] (size_type i, size_type nb) { 197 | const_pointer lo = src + i; 198 | const_pointer hi = lo + nb; 199 | return std::make_pair(lo, hi); 200 | }; 201 | c.stream_pushn_front(prod, nb); 202 | } 203 | 204 | template 205 | void popn_back(Container& c, value_type* dst, size_type nb) { 206 | using const_pointer = const value_type*; 207 | using allocator_type = typename Container::allocator_type; 208 | value_type* p = dst + nb; 209 | auto cons = [&] (const_pointer lo, const_pointer hi) { 210 | size_type d = hi - lo; 211 | p -= d; 212 | fixedcapacity::base::copy(p, lo, d); 213 | }; 214 | c.template stream_popn_back(cons, nb); 215 | } 216 | 217 | template 218 | void popn_front(Container& c, value_type* dst, size_type nb) { 219 | using const_pointer = const value_type*; 220 | using allocator_type = typename Container::allocator_type; 221 | value_type* p = dst; 222 | auto cons = [&] (const_pointer lo, const_pointer hi) { 223 | size_type d = hi - lo; 224 | fixedcapacity::base::copy(p, lo, d); 225 | p += d; 226 | }; 227 | c.template stream_popn_front(cons, nb); 228 | } 229 | 230 | /*---------------------------------------------------------------------*/ 231 | /* Debugging output */ 232 | 233 | template 234 | std::ostream& generic_print_container(std::ostream& out, const Container& seq) { 235 | using value_type = typename Container::value_type; 236 | using size_type = typename Container::size_type; 237 | size_type sz = seq.size(); 238 | out << "["; 239 | seq.for_each([&] (value_type x) { 240 | sz--; 241 | if (sz == 0) 242 | out << x; 243 | else 244 | out << x << ", "; 245 | }); 246 | out << "]"; 247 | return out; 248 | } 249 | 250 | /*---------------------------------------------------------------------*/ 251 | 252 | 253 | /* todo: 254 | * 255 | * - assign 256 | * - at 257 | * - relational operators http://www.cplusplus.com/reference/vector/vector/operators/ 258 | * 259 | */ 260 | 261 | /***********************************************************************/ 262 | 263 | } // end namespace 264 | } // end namespace 265 | } // end namespace 266 | } // end namespace 267 | 268 | #endif /*! _PASL_DATA_CHUNKEDSEQEXTRAS_H_ */ 269 | -------------------------------------------------------------------------------- /include/fixedcapacity.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Fixed capacity vectors 8 | * \file fixedcapacity.hpp 9 | * 10 | */ 11 | 12 | #include "fixedcapacitybase.hpp" 13 | 14 | #ifndef _PASL_DATA_FIXEDCAPACITY_H_ 15 | #define _PASL_DATA_FIXEDCAPACITY_H_ 16 | 17 | namespace pasl { 18 | namespace data { 19 | namespace fixedcapacity { 20 | 21 | /***********************************************************************/ 22 | 23 | /*---------------------------------------------------------------------*/ 24 | /* Heap-allocated fixed-capacity buffers */ 25 | 26 | namespace heap_allocated { 27 | 28 | template > 29 | using ringbuffer_ptr = base::ringbuffer_ptr>; 30 | 31 | template > 32 | using ringbuffer_ptrx = base::ringbuffer_ptrx>; 33 | 34 | template > 35 | using ringbuffer_idx = base::ringbuffer_idx>; 36 | 37 | template > 38 | using stack = base::stack>; 39 | 40 | } 41 | 42 | /*---------------------------------------------------------------------*/ 43 | /* Inline-allocated fixed-capacity arrays */ 44 | 45 | namespace inline_allocated { 46 | 47 | template > 48 | using ringbuffer_ptr = base::ringbuffer_ptr>; 49 | 50 | template > 51 | using ringbuffer_idx = base::ringbuffer_idx>; 52 | 53 | template > 54 | using stack = base::stack>; 55 | 56 | } 57 | 58 | /***********************************************************************/ 59 | 60 | } // end namespace 61 | } // end namespace 62 | } // end namespace 63 | 64 | #endif /*! _PASL_DATA_FIXEDCAPACITY_H_ */ 65 | -------------------------------------------------------------------------------- /include/itemsearch.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Routines for finding an item in a container via binary search 8 | * \file itemsearch.hpp 9 | * 10 | */ 11 | 12 | #include "segment.hpp" 13 | 14 | #ifndef _PASL_DATA_ITEMSEARCH_H_ 15 | #define _PASL_DATA_ITEMSEARCH_H_ 16 | 17 | namespace pasl { 18 | namespace data { 19 | namespace chunkedseq { 20 | namespace itemsearch { 21 | 22 | /***********************************************************************/ 23 | 24 | /*---------------------------------------------------------------------*/ 25 | /* Compare-by-position (i.e., one-based index) 26 | * 27 | * The purpose of this operator is to enable optimizations in item 28 | * search that are specific to indexing (i.e., finding an item 29 | * quickly by using just pointer arithmetic to locate its position in 30 | * the sequence). 31 | */ 32 | 33 | template 34 | class less_than { 35 | public: 36 | bool operator()(Comparable x, Comparable y) { 37 | return x < y; 38 | } 39 | }; 40 | 41 | template 42 | class compare_measured_by_position { 43 | private: 44 | 45 | Position pos; 46 | 47 | public: 48 | 49 | compare_measured_by_position(Position pos) : pos(pos) { } 50 | 51 | bool operator()(Measured m) const { 52 | return Comparator()(pos, Measured_fields::csize(m)); 53 | } 54 | 55 | Position get_position() const { 56 | return pos; 57 | } 58 | 59 | }; 60 | 61 | /* \brief Predicate constructor to define zero-based indexing scheme 62 | * 63 | * Example use: 64 | * 65 | * less_than_by_position p(5); // p(i) = 5 < i 66 | * 67 | * p(1) p(2) p(3) p(4) p(5) p(6) p(7) 68 | * f f f f f t t 69 | */ 70 | template 71 | using less_than_by_position = 72 | compare_measured_by_position>; 73 | 74 | /*---------------------------------------------------------------------*/ 75 | /* Search result type */ 76 | 77 | /*! 78 | * \class search_result 79 | * \brief Result of a search for an item in a sequence 80 | * \tparam Position type of the position used by the search (e.g., pointer, index, etc.) 81 | * \tparam Measured type of the cached measurement of the sequence 82 | */ 83 | template 84 | class search_result { 85 | public: 86 | Position position; 87 | Measured prefix; 88 | search_result() { } 89 | search_result(Position position, Measured prefix) 90 | : position(position), prefix(prefix) { } 91 | }; 92 | 93 | /*---------------------------------------------------------------------*/ 94 | /* Linear search for an item in a segment */ 95 | 96 | template 97 | class search_in_segment { 98 | public: 99 | 100 | using value_type = Item; 101 | using const_pointer = const value_type*; 102 | using segment_type = segment; 103 | 104 | using algebra_type = Algebra; 105 | using measured_type = typename Algebra::value_type; 106 | 107 | using result_type = search_result; 108 | 109 | template 110 | static result_type search_by(segment_type seg, const Measure& meas, measured_type prefix, 111 | const Pred& p) { 112 | measured_type new_prefix = prefix; 113 | const_pointer ptr; 114 | for (ptr = seg.middle; ptr != seg.end; ptr++) { 115 | measured_type m = algebra_type::combine(new_prefix, meas(*ptr)); 116 | if (p(m)) 117 | break; // found it 118 | new_prefix = m; 119 | } 120 | return result_type(ptr, new_prefix); 121 | } 122 | 123 | }; 124 | 125 | /*---------------------------------------------------------------------*/ 126 | /* Linear search for an item in a fixed-capacity queue */ 127 | 128 | class no_size_access { 129 | public: 130 | static constexpr bool enable_index_optimization = false; 131 | 132 | template 133 | static size_t size(Measured& m) { 134 | assert(false); 135 | return 0; 136 | } 137 | template 138 | static size_t csize(Measured m) { 139 | assert(false); 140 | return 0; 141 | } 142 | 143 | }; 144 | 145 | template 146 | class search_in_fixed_capacity_queue { 147 | public: 148 | 149 | using queue_type = Fixedcapacity_queue; 150 | using size_type = size_t; 151 | using value_type = typename queue_type::value_type; 152 | using pointer = value_type*; 153 | 154 | using algebra_type = Algebra; 155 | using measured_type = typename Algebra::value_type; 156 | 157 | using result_type = search_result; 158 | 159 | private: 160 | 161 | using search_in_segment_type = search_in_segment; 162 | using search_in_segment_result_type = typename search_in_segment_type::result_type; 163 | using segment_type = typename search_in_segment_type::segment_type; 164 | 165 | segment_type segment_by_index(const queue_type& items, size_type i) const { 166 | return make_const_segment(items.segment_by_index((int)i)); 167 | } 168 | 169 | public: 170 | 171 | template 172 | result_type operator()(const queue_type& items, const Measure& meas, measured_type prefix, 173 | const Pred& p) const { 174 | 175 | /* reference version 176 | measured_type new_prefix = prefix; 177 | size_t nb = items.size(); 178 | size_t i; 179 | for (i = 0; i < nb; i++) { 180 | measured_type m = algebra_type::combine(new_prefix, meas(items[i])); 181 | if (p(m)) 182 | break; // found it 183 | new_prefix = m; 184 | } 185 | return result_type(i+1, new_prefix); 186 | */ 187 | 188 | size_type sz = size_type(items.size()); 189 | segment_type seg1 = segment_by_index(items, 0); 190 | segment_type seg2 = segment_by_index(items, sz - 1); 191 | if (seg1.begin == seg2.begin) { // no wraparound 192 | assert(seg1.end - seg1.begin == sz); 193 | search_in_segment_result_type res = search_in_segment_type::search_by(seg1, meas, prefix, p); 194 | return result_type(res.position - seg1.begin + 1, res.prefix); 195 | } 196 | // wraparound 197 | search_in_segment_result_type res = search_in_segment_type::search_by(seg1, meas, prefix, p); 198 | size_type i = res.position - seg1.begin; 199 | prefix = res.prefix; 200 | if (res.position != seg1.end) // found in first of two segments 201 | return result_type(i + 1, prefix); 202 | seg2 = segment_type(seg2.begin, seg2.begin, seg2.end); 203 | res = search_in_segment_type::search_by(seg2, meas, prefix, p); 204 | size_type seg1_nb = seg1.end - seg1.begin; 205 | size_type seg2_nb = res.position - seg2.begin; 206 | i = seg1_nb + seg2_nb; 207 | prefix = res.prefix; 208 | return result_type(i + 1, prefix); 209 | 210 | } 211 | 212 | // optimization that is specific to a search for a position (i.e., one-based index) 213 | // the client field of the prefix value returned by this function is the identity value 214 | template 215 | result_type operator()(const queue_type& items, const Measure& meas, measured_type prefix, 216 | const less_than_by_position& p) const { 217 | if (! Size_access::enable_index_optimization) { 218 | // this optimization does not apply 219 | auto q = [&] (measured_type m) { return p(m); }; 220 | return operator()(items, meas, prefix, q); 221 | } 222 | size_type target = p.get_position() + 1; 223 | size_type sz_prefix = Size_access::csize(prefix); 224 | size_type nb_items = size_type(items.size()); 225 | size_type sz_with_items = nb_items + sz_prefix; 226 | assert(target <= sz_with_items + 1); 227 | result_type res; 228 | if (target == sz_with_items + 1) { // target pointing one past last item 229 | res.position = sz_with_items + 1; 230 | res.prefix = algebra_type::identity(); 231 | Size_access::size(res.prefix) = res.position; 232 | } else { // target pointing to an item in the chunk 233 | res.position = target - sz_prefix; 234 | res.prefix = algebra_type::identity(); 235 | Size_access::size(res.prefix) = target - 1; 236 | } 237 | return res; 238 | } 239 | 240 | }; 241 | 242 | /*---------------------------------------------------------------------*/ 243 | /* Search over the items of a chunk */ 244 | 245 | template 249 | class Queue_search=search_in_fixed_capacity_queue> 250 | class search_in_chunk { 251 | public: 252 | 253 | using chunk_type = Chunk; 254 | using queue_type = typename Chunk::queue_type; 255 | using size_type = size_t; 256 | using value_type = typename chunk_type::value_type; 257 | using pointer = value_type*; 258 | 259 | using algebra_type = Algebra; 260 | using measured_type = typename Algebra::value_type; 261 | 262 | using queue_search_type = Queue_search; 263 | 264 | using result_type = typename queue_search_type::result_type; 265 | 266 | public: 267 | 268 | template 269 | result_type operator()(const chunk_type& chunk, const Measure& meas, measured_type prefix, 270 | const Pred& p) const { 271 | queue_search_type search; 272 | return search(chunk.items, meas, prefix, p); 273 | } 274 | 275 | }; 276 | 277 | /***********************************************************************/ 278 | 279 | } // end namespace 280 | } // end namespace 281 | } // end namespace 282 | } // end namespace 283 | 284 | #endif /*! _PASL_DATA_ITEMSEARCH_H_ */ 285 | -------------------------------------------------------------------------------- /include/iterator.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief STL style iterators for our chunked sequences 8 | * \file iterator.hpp 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "itemsearch.hpp" 17 | 18 | #ifndef _PASL_DATA_ITERATOR_H_ 19 | #define _PASL_DATA_ITERATOR_H_ 20 | 21 | namespace pasl { 22 | namespace data { 23 | namespace chunkedseq { 24 | namespace iterator { 25 | 26 | /***********************************************************************/ 27 | 28 | using position_type = enum { begin, end }; 29 | 30 | /*---------------------------------------------------------------------*/ 31 | //! [bidirectional] 32 | /*! 33 | * \class bidirectional 34 | * \ingroup chunkedseq 35 | * \brief Bi-directional iterator 36 | * 37 | * Implements the BidirectionalIterator category of the Standard 38 | * Template Library. 39 | * 40 | */ 41 | template 42 | class bidirectional { 43 | private: 44 | 45 | using config_type = Configuration; 46 | using chunk_pointer = const typename config_type::chunk_type*; 47 | using segment_type = typename config_type::segment_type; 48 | 49 | public: 50 | 51 | using iterator_category = std::bidirectional_iterator_tag; 52 | using value_type = typename config_type::value_type; 53 | using difference_type = typename config_type::difference_type; 54 | using pointer = value_type*; 55 | using reference = value_type&; 56 | using self_type = bidirectional; 57 | 58 | private: 59 | 60 | chunk_pointer cur; 61 | segment_type seg; 62 | 63 | self_type& increment() { 64 | assert(false); // todo 65 | return *this; 66 | } 67 | 68 | self_type& decrement() { 69 | assert(false); // todo 70 | return *this; 71 | } 72 | 73 | public: 74 | 75 | bidirectional(chunk_pointer p) 76 | : cur(p) { 77 | assert(false); // todo 78 | } 79 | 80 | bidirectional() { 81 | assert(false); // todo 82 | } 83 | 84 | /*---------------------------------------------------------------------*/ 85 | /** @name ForwardIterator 86 | */ 87 | ///@{ 88 | 89 | bool operator==(const self_type& other) const { 90 | return seg.middle == other.seg.middle 91 | && seg.end == other.seg.end; 92 | } 93 | 94 | bool operator!=(const self_type& other) const { 95 | return ! (*this == other); 96 | } 97 | 98 | reference operator*() const { 99 | return *seg.middle; 100 | } 101 | 102 | self_type& operator++() { 103 | return increment(); 104 | } 105 | 106 | self_type operator++(int) { 107 | return increment(); 108 | 109 | } 110 | 111 | self_type& operator--() { 112 | return decrement(); 113 | } 114 | 115 | self_type operator--(int) { 116 | return decrement(); 117 | } 118 | 119 | ///@} 120 | 121 | segment_type get_segment() const { 122 | return seg; 123 | } 124 | 125 | }; 126 | 127 | /*---------------------------------------------------------------------*/ 128 | //! [random_access] 129 | /*! 130 | * \class random_access 131 | * \ingroup chunkedseq 132 | * \brief Random-access iterator 133 | * 134 | * Implements the RandomAccessIterator category of the Standard Template 135 | * Library. 136 | * 137 | */ 138 | template < 139 | class Chunkedseq, 140 | class Configuration, 141 | class Pointer, 142 | class Reference, 143 | class Segment 144 | > 145 | class random_access { 146 | private: 147 | 148 | using chunkedseq_type = Chunkedseq; 149 | using config_type = Configuration; 150 | using const_chunkedseq_pointer = const chunkedseq_type*; 151 | using const_chunk_pointer = const typename config_type::chunk_type*; 152 | 153 | public: 154 | 155 | /*---------------------------------------------------------------------*/ 156 | /** @name STL-specific configuration types 157 | */ 158 | ///@{ 159 | using iterator_category = std::random_access_iterator_tag; 160 | using size_type = typename config_type::size_type; 161 | using difference_type = typename config_type::difference_type; 162 | ///@} 163 | 164 | /*---------------------------------------------------------------------*/ 165 | /** @name Container-specific types 166 | */ 167 | ///@{ 168 | using self_type = random_access; 170 | using value_type = typename config_type::value_type; 171 | using pointer = Pointer; 172 | using reference = Reference; 173 | using segment_type = Segment; 174 | ///@} 175 | 176 | /*---------------------------------------------------------------------*/ 177 | /** @name Cached-measurement types 178 | */ 179 | ///@{ 180 | using cache_type = typename config_type::middle_cache_type; 181 | using measured_type = typename cache_type::measured_type; 182 | using algebra_type = typename cache_type::algebra_type; 183 | using measure_type = typename cache_type::measure_type; 184 | ///@} 185 | 186 | /*---------------------------------------------------------------------*/ 187 | 188 | private: 189 | 190 | using chunk_search_type = typename config_type::chunk_search_type; 191 | 192 | using size_access = typename config_type::size_access; 193 | 194 | const_chunkedseq_pointer seq; 195 | const_chunk_pointer cur; 196 | segment_type seg; 197 | 198 | measure_type meas_fct; 199 | 200 | segment_type segment_by_index(const_chunk_pointer p, long pos) { 201 | segment_type result; 202 | /* Perform the coercion below because the segment type returned 203 | * by p->segment_by_index() might not match the segment type 204 | * of the iterator. In particular, the segment type of the 205 | * iterator could be instantiated at "const value_type*", while 206 | * the p->segment_by_index() function returns a segment type 207 | * that is instantiated at "value_type*". 208 | */ 209 | coerce_segment(p->segment_by_index(pos), result); 210 | return result; 211 | } 212 | 213 | /*---------------------------------------------------------------------*/ 214 | 215 | void check() { 216 | #ifndef NDEBUG 217 | size_type sz = size(); 218 | size_type ssz = seq->size(); 219 | if (sz > ssz + 1) 220 | std::cout << "error" << std::endl; 221 | sz = size(); 222 | assert(sz <= ssz + 1); 223 | assert(sz >= 0); 224 | #endif 225 | } 226 | 227 | template 228 | measured_type chunk_search_by(const Pred& p, measured_type prefix) { 229 | chunk_search_type chunk_search; 230 | assert(size_access::csize(prefix) != seq->size()); 231 | cur->annotation.prefix.set_cached(prefix); 232 | auto res = chunk_search(*cur, meas_fct, prefix, p); 233 | size_type pos = res.position; 234 | prefix = res.prefix; 235 | seg = segment_by_index(cur, pos - 1); 236 | if (seg.middle - seg.begin > cur->size()) 237 | cur->segment_by_index(pos - 1); 238 | assert(seg.middle - seg.begin <= cur->size()); 239 | return prefix; 240 | } 241 | 242 | // Updates position of the iterator to the position of the target 243 | // updates cur and seg fields 244 | template 245 | measured_type chunkedseq_search_by(const Pred& p, measured_type prefix) { 246 | bool found; 247 | if (seq->is_buffer(cur)) 248 | cur = nullptr; 249 | prefix = seq->search_for_chunk(p, prefix, found, cur); 250 | if (found) { 251 | prefix = chunk_search_by(p, prefix); 252 | } else { 253 | // make the iterator logically point one past the end of the sequence 254 | assert(size_access::csize(prefix) == seq->size()); 255 | cur = seq->get_chunk_containing_last_item(); 256 | size_type sz_cur = cur->size(); 257 | measured_type m = prefix; 258 | size_access::size(m) = seq->size() - sz_cur; 259 | cur->annotation.prefix.set_cached(m); 260 | if (sz_cur == 0) 261 | seg.begin = seg.end = nullptr; 262 | else 263 | seg = segment_by_index(cur, sz_cur - 1); 264 | seg.middle = seg.end; 265 | } 266 | check(); 267 | return prefix; 268 | } 269 | 270 | template 271 | measured_type chunkedseq_search_by(const Pred& p) { 272 | return chunkedseq_search_by(p, algebra_type::identity()); 273 | } 274 | 275 | self_type new_iterator_at(size_type sz) const { 276 | self_type it(*this); 277 | it.search_by_one_based_index(sz); 278 | return it; 279 | } 280 | 281 | self_type& increment_by(size_type n) { 282 | check(); 283 | size_type orig_sz = size(); 284 | pointer m = seg.middle + n; 285 | if (m >= seg.end) 286 | search_by_one_based_index(orig_sz + n); 287 | else 288 | seg.middle = m; 289 | assert(size() == orig_sz + n); 290 | check(); 291 | return *this; 292 | } 293 | 294 | self_type& decrement_by(size_type n) { 295 | check(); 296 | size_type orig_sz = size(); 297 | pointer m = seg.middle - n; 298 | if (m < seg.begin) 299 | search_by_one_based_index(orig_sz - n); 300 | else 301 | seg.middle = m; 302 | assert(size() == orig_sz - n); 303 | check(); 304 | return *this; 305 | } 306 | 307 | static size_type nb_before_middle(const_chunk_pointer c, segment_type seg) { 308 | if (seg.middle == seg.end) { 309 | if (seg.middle == seg.begin) 310 | return 0; 311 | return c->index_of_pointer(seg.middle - 1) + 1; 312 | } else { 313 | return c->index_of_pointer(seg.middle); 314 | } 315 | } 316 | 317 | size_type size_of_prefix() const { 318 | measured_type prefix_of_chunk = cur->annotation.prefix.template get_cached(); 319 | size_type nb_items_before_chunk = size_access::csize(prefix_of_chunk); 320 | size_type nb_items_before_seg_middle = nb_before_middle(cur, seg); 321 | return nb_items_before_chunk + nb_items_before_seg_middle; 322 | } 323 | 324 | void search_by_one_based_index(size_type i) { 325 | using predicate_type = itemsearch::less_than_by_position; 326 | predicate_type p(i - 1); 327 | chunkedseq_search_by(p); 328 | size_type sz = size(); 329 | size_type ssz = seq->size(); 330 | assert(sz <= ssz + 1); 331 | assert(sz == i); 332 | } 333 | 334 | void search_by_zero_based_index(size_type i) { 335 | search_by_one_based_index(i + 1); 336 | } 337 | 338 | /*---------------------------------------------------------------------*/ 339 | 340 | public: 341 | 342 | random_access(const_chunkedseq_pointer seq, const measure_type& meas, position_type pos) 343 | : seq(seq), cur(nullptr), meas_fct(meas) { 344 | search_by_one_based_index(1); 345 | switch (pos) { 346 | case begin: { 347 | search_by_one_based_index(1); 348 | break; 349 | } 350 | case end: { 351 | search_by_one_based_index(seq->size() + 1); 352 | break; 353 | } 354 | } 355 | 356 | } 357 | 358 | random_access() : seq(nullptr), cur(nullptr) { } 359 | 360 | /*---------------------------------------------------------------------*/ 361 | /** @name ForwardIterator 362 | */ 363 | ///@{ 364 | 365 | bool operator==(const self_type& other) const { 366 | assert(seq == other.seq); 367 | bool eq = seg.middle == other.seg.middle 368 | && seg.end == other.seg.end; 369 | #ifndef NDEBUG 370 | size_type sz = size(); 371 | size_type sz_other = other.size(); 372 | assert(eq ? sz == sz_other : sz != sz_other); 373 | #endif 374 | return eq; 375 | } 376 | 377 | bool operator!=(const self_type& other) const { 378 | return ! (*this == other); 379 | } 380 | 381 | reference operator*() const { 382 | return *seg.middle; 383 | } 384 | 385 | // prefix ++ 386 | self_type& operator++() { 387 | return increment_by(1); 388 | } 389 | 390 | // postfix ++ 391 | self_type operator++(int) { 392 | self_type result(*this); 393 | ++(*this); 394 | return result; 395 | } 396 | 397 | // prefix -- 398 | self_type& operator--() { 399 | return decrement_by(1); 400 | } 401 | 402 | // postfix -- 403 | self_type operator--(int) { 404 | self_type result(*this); 405 | --(*this); 406 | return result; 407 | } 408 | 409 | ///@} 410 | 411 | /*---------------------------------------------------------------------*/ 412 | /** @name RandomAccessIterator 413 | */ 414 | ///@{ 415 | 416 | self_type& operator+=(const size_type n) { 417 | return increment_by(n); 418 | } 419 | 420 | self_type operator+(const self_type& other) const { 421 | return new_iterator_at(size() + other.size()); 422 | } 423 | 424 | self_type operator+(const size_type n) const { 425 | return new_iterator_at(size() + n); 426 | } 427 | 428 | self_type& operator-=(const size_type n) { 429 | return decrement_by(n); 430 | } 431 | 432 | difference_type operator-(const self_type& other) const { 433 | return size() - other.size(); 434 | } 435 | 436 | self_type operator-(const size_type n) const { 437 | size_type sz = size(); 438 | assert(sz > n); 439 | return new_iterator_at(sz - n); 440 | } 441 | 442 | reference operator[](const size_type n) const { 443 | return *(*this + n); 444 | } 445 | 446 | bool operator<(const self_type& other) const { 447 | return size() < other.size(); 448 | } 449 | 450 | bool operator>(const self_type& other) const { 451 | return size() > other.size(); 452 | } 453 | 454 | bool operator<=(const self_type& other) const { 455 | return size() <= other.size(); 456 | } 457 | 458 | bool operator>=(const self_type& other) const { 459 | return size() >= other.size(); 460 | } 461 | 462 | ///@} 463 | 464 | /*---------------------------------------------------------------------*/ 465 | /** @name Item search 466 | */ 467 | ///@{ 468 | 469 | /*! 470 | * \brief Returns the number of items preceding and including the item 471 | * pointed to by the iterator 472 | * 473 | * #### Complexity #### 474 | * Constant time. 475 | * 476 | */ 477 | size_type size() const { 478 | return size_of_prefix() + 1; 479 | } 480 | 481 | template 482 | void search_by(const Pred& p) { 483 | auto q = [&] (measured_type m) { 484 | return p(size_access::cclient(m)); 485 | }; 486 | chunkedseq_search_by(q, algebra_type::identity()); 487 | } 488 | 489 | segment_type get_segment() const { 490 | return seg; 491 | } 492 | 493 | ///@} 494 | 495 | }; 496 | 497 | /***********************************************************************/ 498 | 499 | } // end namespace 500 | } // end namespace 501 | } // end namespace 502 | } // end namespace 503 | 504 | #endif /*! _PASL_DATA_ITERATOR_H_ */ 505 | -------------------------------------------------------------------------------- /include/measure.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Definitions of a few standard measure functors 8 | * \file measure.hpp 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #ifndef _PASL_DATA_MEASURE_H_ 16 | #define _PASL_DATA_MEASURE_H_ 17 | 18 | namespace pasl { 19 | namespace data { 20 | namespace measure { 21 | 22 | /***********************************************************************/ 23 | 24 | /*---------------------------------------------------------------------*/ 25 | //! [trivial] 26 | template 27 | class trivial { 28 | public: 29 | 30 | using value_type = Item; 31 | using measured_type = Measured; 32 | 33 | measured_type operator()(const value_type& v) const { 34 | return measured_type(); 35 | } 36 | 37 | measured_type operator()(const value_type* lo, const value_type* hi) const { 38 | return measured_type(); 39 | } 40 | 41 | }; 42 | //! [trivial] 43 | 44 | /*---------------------------------------------------------------------*/ 45 | //! [uniform] 46 | template 47 | class uniform { 48 | public: 49 | 50 | using value_type = Item; 51 | using measured_type = Measured; 52 | const int item_weight = Item_weight; 53 | 54 | measured_type operator()(const value_type& v) const { 55 | return measured_type(item_weight); 56 | } 57 | 58 | measured_type operator()(const value_type* lo, const value_type* hi) const { 59 | return measured_type(hi - lo); 60 | } 61 | }; 62 | //! [uniform] 63 | 64 | /*---------------------------------------------------------------------*/ 65 | //! [weight] 66 | template 67 | class weight { 68 | public: 69 | 70 | using value_type = Item; 71 | using measured_type = Weight; 72 | using client_weight_fct_type = Client_weight_fct; 73 | 74 | private: 75 | 76 | client_weight_fct_type client_weight_fct; 77 | 78 | // for debugging purposes 79 | bool initialized; 80 | 81 | public: 82 | 83 | weight() : initialized(false) { } 84 | 85 | weight(const client_weight_fct_type& env) 86 | : client_weight_fct(env), initialized(true) { } 87 | 88 | measured_type operator()(const value_type& v) const { 89 | return client_weight_fct(v); 90 | } 91 | 92 | measured_type operator()(const value_type* lo, const value_type* hi) const { 93 | measured_type m = 0; 94 | for (auto p = lo; p < hi; p++) 95 | m += operator()(*p); 96 | return m; 97 | } 98 | 99 | client_weight_fct_type get_env() const { 100 | assert(initialized); 101 | return client_weight_fct; 102 | } 103 | 104 | void set_env(client_weight_fct_type wf) { 105 | client_weight_fct = wf; 106 | initialized = true; 107 | } 108 | 109 | }; 110 | //! [weight] 111 | 112 | /*---------------------------------------------------------------------*/ 113 | //! [measured_pair] 114 | template 115 | class measured_pair { 116 | public: 117 | Measured1 value1; 118 | Measured2 value2; 119 | measured_pair() { } 120 | measured_pair(const Measured1& value1, const Measured2& value2) 121 | : value1(value1), value2(value2) { } 122 | }; 123 | 124 | template 125 | measured_pair make_measured_pair(Measured1 m1, Measured2 m2) { 126 | measured_pair m(m1, m2); 127 | return m; 128 | } 129 | //! [measured_pair] 130 | 131 | /*---------------------------------------------------------------------*/ 132 | //! [combiner] 133 | template 134 | class combiner { 135 | public: 136 | 137 | using measure1_type = Measure1; 138 | using measure2_type = Measure2; 139 | 140 | using value_type = Item; 141 | using measured_type = measured_pair; 142 | 143 | measure1_type meas1; 144 | measure2_type meas2; 145 | 146 | combiner() { } 147 | 148 | combiner(const measure1_type meas1) 149 | : meas1(meas1) { } 150 | 151 | combiner(const measure2_type meas2) 152 | : meas2(meas2) { } 153 | 154 | combiner(const measure1_type meas1, const measure2_type meas2) 155 | : meas1(meas1), meas2(meas2) { } 156 | 157 | measured_type operator()(const value_type& v) const { 158 | return make_measured_pair(meas1(v), meas2(v)); 159 | } 160 | 161 | measured_type operator()(const value_type* lo, const value_type* hi) const { 162 | return make_measured_pair(meas1(lo, hi), meas2(lo, hi)); 163 | } 164 | 165 | }; 166 | //! [combiner] 167 | 168 | /***********************************************************************/ 169 | 170 | } // end namespace 171 | } // end namespace 172 | } // end namespace 173 | 174 | #endif /*! _PASL_DATA_MEASURE_H_ */ 175 | -------------------------------------------------------------------------------- /include/segment.hpp: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2015 Umut A. Acar, Arthur Chargueraud, and Mike Rainey 3 | * 4 | * This software may be modified and distributed under the terms 5 | * of the MIT license. See the LICENSE file for details. 6 | * 7 | * \brief Memory segment 8 | * \file segment.hpp 9 | * 10 | */ 11 | 12 | #ifndef _PASL_DATA_SEGMENT_H_ 13 | #define _PASL_DATA_SEGMENT_H_ 14 | 15 | namespace pasl { 16 | namespace data { 17 | 18 | /***********************************************************************/ 19 | 20 | /*---------------------------------------------------------------------*/ 21 | /*! \brief Segment descriptor 22 | * 23 | * A segment consists of a pointer along with a right-open interval 24 | * that describes a contiguous region of memory surrounding the 25 | * pointer. 26 | * 27 | * Invariant: 28 | * `begin <= middle < end` 29 | * 30 | */ 31 | //! [segment] 32 | template 33 | class segment { 34 | public: 35 | 36 | using pointer_type = Pointer; 37 | 38 | // points to the first cell of the interval 39 | pointer_type begin; 40 | // points to a cell contained in the interval 41 | pointer_type middle; 42 | // points to the cell that is one cell past the last cell of interval 43 | pointer_type end; 44 | 45 | segment() 46 | : begin(nullptr), middle(nullptr), end(nullptr) { } 47 | 48 | segment(pointer_type begin, pointer_type middle, pointer_type end) 49 | : begin(begin), middle(middle), end(end) { } 50 | 51 | }; 52 | //! [segment] 53 | 54 | /*---------------------------------------------------------------------*/ 55 | 56 | /*! \brief Returns a segment that contains pointer `p` in a given ringbuffer 57 | * 58 | * \param p pointer on an item in the ringbuffer 59 | * \param fr pointer on the first item 60 | * \param bk pointer on the last item 61 | * \param a pointer on the first cell of the array 62 | * \param capacity size in number of items of the array 63 | */ 64 | template 65 | segment segment_of_ringbuffer(Pointer p, Pointer fr, Pointer bk, Pointer a, int capacity) { 66 | segment seg; 67 | assert(p >= a); 68 | assert(p < a + capacity); 69 | seg.middle = p; 70 | if (fr <= bk) { // no wraparound 71 | seg.begin = fr; 72 | seg.end = bk + 1; 73 | } else if (p >= fr) { // p points into first segment 74 | seg.begin = fr; 75 | seg.end = a + capacity; 76 | } else { // p points into second segment 77 | assert(p <= bk); 78 | seg.begin = a; 79 | seg.end = bk + 1; 80 | } 81 | assert(seg.begin <= p); 82 | assert(seg.middle == p); 83 | assert(p < seg.end); 84 | return seg; 85 | } 86 | 87 | template 88 | segment make_const_segment(segment seg) { 89 | segment res; 90 | res.begin = seg.begin; 91 | res.middle = seg.middle; 92 | res.end = seg.end; 93 | return res; 94 | } 95 | 96 | template 97 | void coerce_segment(segment src, segment& dst) { 98 | dst = make_const_segment(src); 99 | } 100 | 101 | template 102 | void coerce_segment(segment src, segment& dst) { 103 | dst = src; 104 | } 105 | 106 | /***********************************************************************/ 107 | 108 | } // end namespace 109 | } // end namespace 110 | 111 | #endif /*! _PASL_DATA_SEGMENT_H_ */ 112 | -------------------------------------------------------------------------------- /script/benchmark.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {}, 2 | stdenv ? pkgs.stdenv, 3 | sources ? import ./default-sources.nix, 4 | gperftools ? pkgs.gperftools, 5 | gcc ? pkgs.gcc, 6 | php ? pkgs.php, 7 | sc15-pdfs ? import ../../sc15-pdfs/script/default.nix { }, 8 | buildDocs ? false 9 | }: 10 | 11 | let 12 | 13 | callPackage = pkgs.lib.callPackageWith (pkgs // sources // self); 14 | 15 | self = { 16 | 17 | gperftools = gperftools; 18 | gcc = gcc; 19 | php = php; 20 | 21 | buildDocs = buildDocs; 22 | 23 | pbench = callPackage "${sources.pbenchSrc}/script/default.nix" { }; 24 | cmdline = callPackage "${sources.cmdlineSrc}/script/default.nix" { }; 25 | chunkedseq = callPackage "${sources.chunkedseqSrc}/script/default.nix" { }; 26 | 27 | }; 28 | 29 | in 30 | 31 | with self; 32 | 33 | stdenv.mkDerivation rec { 34 | name = "chunkedseq-benchmark"; 35 | 36 | src = sources.chunkedseqSrc; 37 | 38 | buildInputs = 39 | let pandoc = 40 | pkgs.haskellPackages.ghcWithPackages (pkgs: with pkgs; [pandoc-types pandoc-citeproc]); 41 | in 42 | [ gperftools gcc pbench cmdline chunkedseq 43 | pandoc pkgs.texlive.combined.scheme-small pkgs.ocaml 44 | pkgs.makeWrapper ]; 45 | 46 | configurePhase = 47 | let settingsScript = pkgs.writeText "settings.sh" '' 48 | PBENCH_PATH=../pbench/ 49 | CHUNKEDSEQ_PATH=${chunkedseq}/include/ 50 | ''; 51 | in 52 | '' 53 | cp -r --no-preserve=mode ${pbench} pbench 54 | cp ${settingsScript} bench/settings.sh 55 | ''; 56 | 57 | buildPhase = 58 | let doc = if buildDocs then '' 59 | '' else ""; 60 | in 61 | '' 62 | export PATH=${php}/bin:$PATH 63 | make -C bench chunkedseq.pbench do_fifo.exe bench.exe -j 64 | ''; 65 | 66 | installPhase = 67 | let doc = 68 | if buildDocs then '' 69 | '' 70 | else ""; 71 | in 72 | '' 73 | mkdir -p $out/bench 74 | cp bench/chunkedseq.pbench bench/do_fifo.exe bench/bench.exe bench/timeout.out $out/bench 75 | wrapProgram $out/bench/chunkedseq.pbench --prefix PATH ":" ${pkgs.R}/bin \ 76 | --prefix PATH ":" ${pkgs.texlive.combined.scheme-small}/bin \ 77 | --prefix PATH ":" ${gcc}/bin \ 78 | --prefix PATH ":" ${php}/bin \ 79 | --prefix PATH ":" ${pkgs.ipget}/bin \ 80 | --prefix PATH ":" $out/bench \ 81 | --prefix LD_LIBRARY_PATH ":" ${gcc}/lib \ 82 | --prefix LD_LIBRARY_PATH ":" ${gcc}/lib64 \ 83 | --prefix PATH ":" ${sc15-pdfs}/bench \ 84 | --add-flags "-skip make" 85 | ${doc} 86 | ''; 87 | 88 | meta = { 89 | description = "A script for building a benchmarking environment for chunkedseq"; 90 | license = "MIT"; 91 | homepage = http://deepsea.inria.fr/chunkedseq; 92 | }; 93 | } 94 | -------------------------------------------------------------------------------- /script/default-sources.nix: -------------------------------------------------------------------------------- 1 | let pkgs = import {}; in 2 | 3 | { 4 | 5 | cmdlineSrc = pkgs.fetchFromGitHub { 6 | owner = "deepsea-inria"; 7 | repo = "cmdline"; 8 | rev = "c5f96b4aecb2019b5a690176195d37f7df3ed34b"; 9 | sha256 = "1rz9bfdd5242gy3vq4n9vj2rcr5pwp0j4cjycpn3pm7rnwrrcjnh"; 10 | }; 11 | 12 | pbenchSrc = pkgs.fetchFromGitHub { 13 | owner = "deepsea-inria"; 14 | repo = "pbench"; 15 | rev = "6d862442713cae93153c439a3e5e5867e95af958"; 16 | sha256 = "1qdsl2amaqkckp2r2s4j5az8b0bpkbrgf8nc0zp575l1yjdzi2hh"; 17 | }; 18 | 19 | chunkedseqSrc = pkgs.fetchFromGitHub { 20 | owner = "deepsea-inria"; 21 | repo = "chunkedseq"; 22 | rev = "2c54d8f289b75397e783ebf3a91e3881924c6a39"; 23 | sha256 = "08bx2i63bmawm6qz1kr9f8pj3ccl7ccpg9vhzb38bma7zv530dn3"; 24 | }; 25 | 26 | } 27 | -------------------------------------------------------------------------------- /script/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {}, 2 | stdenv ? pkgs.stdenv, 3 | chunkedseqSrc ? ../., 4 | buildDocs ? false 5 | }: 6 | 7 | stdenv.mkDerivation rec { 8 | name = "chunkedseq"; 9 | 10 | src = chunkedseqSrc; 11 | 12 | buildInputs = 13 | if buildDocs then 14 | let pandocTypes = pkgs.haskellPackages.ghcWithPackages (pkgs: with pkgs; [pandoc-types]); 15 | in 16 | [ pkgs.pandoc pandocTypes pkgs.texlive.combined.scheme-small ] 17 | else 18 | []; 19 | 20 | buildPhase = if buildDocs then '' 21 | make -C doc chunkedseq.pdf chunkedseq.html -j 22 | '' else ""; 23 | 24 | installPhase = 25 | let doc = 26 | if buildDocs then '' 27 | mkdir -p $out/doc/ 28 | cp doc/chunkedseq.pdf doc/chunkedseq.md doc/chunkedseq.html doc/chunkedseq.css $out/doc/ 29 | '' 30 | else ""; 31 | in 32 | '' 33 | mkdir -p $out/include/ 34 | cp include/*.hpp $out/include 35 | cp -r examples $out/ 36 | ${doc} 37 | ''; 38 | 39 | meta = { 40 | description = "A container data structure for representing sequences by many fixed-capacity heap-allocated buffers (i.e., chunks)."; 41 | license = "MIT"; 42 | homepage = http://deepsea.inria.fr/chunkedseq; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /script/latest-sources.nix: -------------------------------------------------------------------------------- 1 | with import {}; 2 | 3 | with builtins; 4 | with lib; 5 | 6 | let sanitiseName = stringAsChars (c: if elem c (lowerChars ++ upperChars) 7 | then c else ""); 8 | 9 | fetchGitHashless = args: stdenv.lib.overrideDerivation 10 | # Use a dummy hash, to appease fetchgit's assertions 11 | (fetchgit (args // { sha256 = hashString "sha256" args.url; })) 12 | 13 | # Remove the hash-checking 14 | (old: { 15 | outputHash = null; 16 | outputHashAlgo = null; 17 | outputHashMode = null; 18 | sha256 = null; 19 | }); 20 | 21 | # Get the commit ID for the given ref in the given repo 22 | latestGitCommit = { url, ref ? "HEAD" }: 23 | runCommand "repo-${sanitiseName ref}-${sanitiseName url}" 24 | { 25 | # Avoids caching. This is a cheap operation and needs to be up-to-date 26 | version = toString currentTime; 27 | 28 | # Required for SSL 29 | GIT_SSL_CAINFO = "${cacert}/etc/ssl/certs/ca-bundle.crt"; 30 | 31 | buildInputs = [ git gnused ]; 32 | } 33 | '' 34 | REV=$(git ls-remote "${url}" "${ref}") || exit 1 35 | 36 | printf '"%s"' $(echo "$REV" | 37 | head -n1 | 38 | sed -e 's/\s.*//g' ) > "$out" 39 | ''; 40 | 41 | fetchLatestGit = { url, ref ? "HEAD" }@args: 42 | with { rev = import (latestGitCommit { inherit url ref; }); }; 43 | fetchGitHashless (removeAttrs (args // { inherit rev; }) [ "ref" ]); 44 | 45 | in 46 | 47 | { 48 | 49 | cmdlineSrc = fetchLatestGit { 50 | url = "https://github.com/deepsea-inria/cmdline.git"; 51 | }; 52 | 53 | pbenchSrc = fetchLatestGit { 54 | url = "https://github.com/deepsea-inria/pbench.git"; 55 | }; 56 | 57 | chunkedseqSrc = fetchLatestGit { 58 | url = "https://github.com/deepsea-inria/chunkedseq.git"; 59 | }; 60 | 61 | sc15pdfs = fetchLatestGit { 62 | url = "https://github.com/deepsea-inria/sc15-pdfs.git"; 63 | }; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /script/local-sources.nix: -------------------------------------------------------------------------------- 1 | let pkgs = import {}; in 2 | 3 | { 4 | 5 | cmdlineSrc = ../../cmdline; 6 | 7 | pbenchSrc = ../../pbench; 8 | 9 | chunkedseqSrc = ../../chunkedseq; 10 | 11 | sc15pdfs = ../../sc15-pdfs; 12 | 13 | } 14 | --------------------------------------------------------------------------------