1 /* 2 * Copyright (c) 2016, Facebook, Inc. 3 * All rights reserved. 4 * 5 * This source code is licensed under the BSD-style license found in the 6 * LICENSE file in the root directory of this source tree. An additional grant 7 * of patent rights can be found in the PATENTS file in the same directory. 8 */ 9 10 #ifndef FATAL_INCLUDE_fatal_string_tokenizer_h 11 #define FATAL_INCLUDE_fatal_string_tokenizer_h 12 13 #include <fatal/container/uninitialized.h> 14 #include <fatal/string/string_view.h> 15 #include <fatal/type/traits.h> 16 17 #include <type_traits> 18 #include <utility> 19 20 namespace fatal { 21 22 template <typename Token, char Delimiter> 23 struct tokenizer { 24 using token = Token; 25 using delimiter = std::integral_constant<char, Delimiter>; 26 27 template <typename... Args, typename = safe_overload<tokenizer, Args...>> tokenizertokenizer28 explicit tokenizer(Args &&...args): data_(std::forward<Args>(args)...) {} 29 30 struct const_iterator { const_iteratortokenizer::const_iterator31 const_iterator(const_iterator const &rhs): 32 data_(rhs.data_) 33 { 34 token_.construct(*rhs.token_); 35 } 36 const_iteratortokenizer::const_iterator37 const_iterator(const_iterator &&rhs): 38 data_(std::move(rhs.data_)) 39 { 40 token_.construct(std::move(*rhs.token_)); 41 } 42 const_iteratortokenizer::const_iterator43 explicit const_iterator(string_view data): 44 data_(data) 45 { 46 token_.construct(data_.seek_past(delimiter::value)); 47 } 48 49 const_iterator &operator ++() { 50 token_.destroy(); 51 token_.construct(data_.seek_past(delimiter::value)); 52 return *this; 53 } 54 55 const_iterator &operator ++(int) { 56 auto copy(*this); 57 ++*this; 58 return copy; 59 } 60 61 token const *operator ->() const { return token_.ptr(); } 62 token const &operator *() const { return *token_; } 63 64 bool operator ==(const_iterator const &rhs) const { 65 return data_.begin() == rhs.data_.begin() 66 && data_.end() == rhs.data_.end() 67 && *token_ == *rhs.token_; 68 } 69 70 bool operator !=(const_iterator const &rhs) const { 71 return !(*this == rhs); 72 } 73 74 private: 75 string_view data_; 76 uninitialized<token, true> token_; 77 }; 78 cbegintokenizer79 const_iterator cbegin() const { return const_iterator(data_); } 80 begintokenizer81 const_iterator begin() const { return cbegin(); } 82 cendtokenizer83 const_iterator cend() const { 84 return const_iterator(string_view(data_.end(), data_.end())); 85 } 86 endtokenizer87 const_iterator end() const { return cend(); } 88 emptytokenizer89 bool empty() const { return !data_; } 90 91 bool operator ==(tokenizer const &rhs) const { 92 return data_.begin() == rhs.data_.begin() 93 && data_.end() == rhs.data_.end(); 94 } 95 96 bool operator !=(tokenizer const &rhs) const { return !(*this == rhs); } 97 98 private: 99 string_view data_; 100 }; 101 102 103 using colon_tokenizer = tokenizer<string_view, ':'>; 104 using comma_tokenizer = tokenizer<string_view, ','>; 105 using line_tokenizer = tokenizer<string_view, '\n'>; 106 using semicolon_tokenizer = tokenizer<string_view, ';'>; 107 using space_tokenizer = tokenizer<string_view, ' '>; 108 109 using csv_tokenizer = tokenizer<comma_tokenizer, '\n'>; 110 111 } // namespace fatal { 112 113 #endif // FATAL_INCLUDE_fatal_string_tokenizer_h 114