diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2014-02-04 23:18:54 -0800 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2014-02-06 11:18:37 -0800 |
commit | 9215c35975be745628e8188473154c7e476add55 (patch) | |
tree | 14d4f5d51381f8a59803233c24dfafc846ddf583 /src/common | |
parent | 9544985ccbb20d7f8377c63a4e59d1ff97b844ac (diff) | |
download | tmwa-9215c35975be745628e8188473154c7e476add55.tar.gz tmwa-9215c35975be745628e8188473154c7e476add55.tar.bz2 tmwa-9215c35975be745628e8188473154c7e476add55.tar.xz tmwa-9215c35975be745628e8188473154c7e476add55.zip |
Wrap remaining FDs in a class
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/core.cpp | 2 | ||||
-rw-r--r-- | src/common/iter.hpp | 97 | ||||
-rw-r--r-- | src/common/iter_test.cpp | 82 | ||||
-rw-r--r-- | src/common/socket.cpp | 181 | ||||
-rw-r--r-- | src/common/socket.hpp | 30 | ||||
-rw-r--r-- | src/common/utils2.hpp | 53 |
6 files changed, 294 insertions, 151 deletions
diff --git a/src/common/core.cpp b/src/common/core.cpp index fe2f660..d57e970 100644 --- a/src/common/core.cpp +++ b/src/common/core.cpp @@ -78,8 +78,6 @@ void sig_proc(int) */ int main(int argc, char **argv) { - do_socket(); - // ZString args[argc]; is (deliberately!) not supported by clang yet ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString))); for (int i = 0; i < argc; ++i) diff --git a/src/common/iter.hpp b/src/common/iter.hpp new file mode 100644 index 0000000..5b39588 --- /dev/null +++ b/src/common/iter.hpp @@ -0,0 +1,97 @@ +#ifndef TMWA_COMMON_ITER_HPP +#define TMWA_COMMON_ITER_HPP +// iter.hpp - tools for dealing with iterators +// +// Copyright © 2012-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +# include "../sanity.hpp" + +# include <iterator> + + +/// Simple class to use a pair of iterators with foreach +template<class It> +class IteratorPair +{ + It _b, _e; +public: + IteratorPair(It b, It e) + : _b(b), _e(e) + {} + + It begin() { return _b; } + It end() { return _e; } +}; + +template<class It> +IteratorPair<It> iterator_pair(It b, It e) +{ + return {b, e}; +} + +template<class T> +class PassthroughMath +{ +public: + static + T inced(T v) { return ++v; } +}; + +// An iterator that just directly contains an integer-like value +// TODO port this once the new integer API happens +template<class T, class Math=PassthroughMath<T>> +class ValueIterator +{ + T value; +public: + typedef std::forward_iterator_tag iterator_category; + typedef void difference_type; + typedef T value_type; + typedef void reference; + typedef void pointer; +public: + ValueIterator(T v) + : value(v) + {} + + T operator *() + { + return value; + } + ValueIterator& operator++ () + { + value = Math::inced(value); + return *this; + } + friend bool operator == (ValueIterator l, ValueIterator r) + { + return l.value == r.value; + } + friend bool operator != (ValueIterator l, ValueIterator r) + { + return !(l == r); + } +}; + +template<class T> +IteratorPair<ValueIterator<T>> value_range(T b, T e) +{ + return {b, e}; +} + +#endif // TMWA_COMMON_ITER_HPP diff --git a/src/common/iter_test.cpp b/src/common/iter_test.cpp new file mode 100644 index 0000000..647ebf9 --- /dev/null +++ b/src/common/iter_test.cpp @@ -0,0 +1,82 @@ +#include "iter.hpp" + +#include <gtest/gtest.h> + +#include "../strings/xstring.hpp" + +TEST(iterpair, string) +{ + IteratorPair<ValueIterator<char>> pair = value_range('0', ':'); + const char *str = "0123456789"; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), str)); +} + +TEST(iterpair, signed8) +{ + IteratorPair<ValueIterator<int8_t>> pair = value_range(int8_t(-128), int8_t(127)); + int8_t arr[255] = + { + -128, -127, -126, -125, -124, -123, -122, -121, -120, + -119, -118, -117, -116, -115, -114, -113, -112, -111, -110, + -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, + -99, -98, -97, -96, -95, -94, -93, -92, -91, -90, + -89, -88, -87, -86, -85, -84, -83, -82, -81, -80, + -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, + -69, -68, -67, -66, -65, -64, -63, -62, -61, -60, + -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, + -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, + -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, + -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, + -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, + -9, -8, -7, -6, -5, -4, -3, -2, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, + }; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr + 0)); +} + +TEST(iterpair, unsigned8) +{ + IteratorPair<ValueIterator<uint8_t>> pair = value_range(uint8_t(0), uint8_t(255)); + uint8_t arr[255] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, + 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, + 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, + 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 250, 251, 252, 253, 254, + }; + EXPECT_TRUE(std::equal(pair.begin(), pair.end(), arr)); +} diff --git a/src/common/socket.cpp b/src/common/socket.cpp index 1c5bcbc..b5f6379 100644 --- a/src/common/socket.cpp +++ b/src/common/socket.cpp @@ -19,7 +19,8 @@ #include "../poison.hpp" static -fd_set readfds; +io::FD_Set readfds; +static int fd_max; static @@ -29,9 +30,35 @@ const uint32_t WFIFO_SIZE = 65536; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" +static std::array<std::unique_ptr<Session>, FD_SETSIZE> session; #pragma GCC diagnostic pop +void set_session(io::FD fd, std::unique_ptr<Session> sess) +{ + int f = fd.uncast_dammit(); + assert (0 <= f && f < FD_SETSIZE); + session[f] = std::move(sess); +} +Session *get_session(io::FD fd) +{ + int f = fd.uncast_dammit(); + if (0 <= f && f < FD_SETSIZE) + return session[f].get(); + return nullptr; +} +void reset_session(io::FD fd) +{ + int f = fd.uncast_dammit(); + assert (0 <= f && f < FD_SETSIZE); + session[f] = nullptr; +} +int get_fd_max() { return fd_max; } +IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds() +{ + return {io::FD::cast_dammit(0), io::FD::cast_dammit(fd_max)}; +} + /// clean up by discarding handled bytes inline void RFIFOFLUSH(Session *s) @@ -68,7 +95,7 @@ void recv_to_fifo(Session *s) if (s->eof) return; - ssize_t len = read(s->fd, &s->rdata[s->rdata_size], + ssize_t len = s->fd.read(&s->rdata[s->rdata_size], RFIFOSPACE(s)); if (len > 0) @@ -88,7 +115,7 @@ void send_from_fifo(Session *s) if (s->eof) return; - ssize_t len = write(s->fd, &s->wdata[0], s->wdata_size); + ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size); if (len > 0) { @@ -120,53 +147,50 @@ void connect_client(Session *ls) struct sockaddr_in client_address; socklen_t len = sizeof(client_address); - int fd = accept(ls->fd, reinterpret_cast<struct sockaddr *>(&client_address), &len); - if (fd == -1) + io::FD fd = ls->fd.accept(reinterpret_cast<struct sockaddr *>(&client_address), &len); + if (fd == io::FD()) { perror("accept"); return; } - if (fd >= SOFT_LIMIT) + if (fd.uncast_dammit() >= SOFT_LIMIT) { - FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd); - shutdown(fd, SHUT_RDWR); - close(fd); + FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd.uncast_dammit()); + fd.shutdown(SHUT_RDWR); + fd.close(); return; } - if (fd_max <= fd) + if (fd_max <= fd.uncast_dammit()) { - fd_max = fd + 1; + fd_max = fd.uncast_dammit() + 1; } const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! /// Testing shows this is indeed a good idea. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); // Linux-ism: Set socket options to optimize for thin streams // See http://lwn.net/Articles/308919/ and // Documentation/networking/tcp-thin.txt .. Kernel 3.2+ #ifdef TCP_THIN_LINEAR_TIMEOUTS - setsockopt(fd, IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes); #endif #ifdef TCP_THIN_DUPACK - setsockopt(fd, IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes); #endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); - session[fd] = make_unique<Session>(); - Session *s = session[fd].get(); + set_session(fd, make_unique<Session>()); + Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); s->wdata.new_(WFIFO_SIZE); @@ -184,27 +208,27 @@ void connect_client(Session *ls) Session *make_listen_port(uint16_t port) { struct sockaddr_in server_address; - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) + io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); + if (fd == io::FD()) { perror("socket"); return nullptr; } - if (fd_max <= fd) - fd_max = fd + 1; + if (fd_max <= fd.uncast_dammit()) + fd_max = fd.uncast_dammit() + 1; - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! // I'm not convinced this is a good idea; although in minimizes the // latency for an individual write, it increases traffic in general. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; #pragma GCC diagnostic push @@ -216,25 +240,22 @@ Session *make_listen_port(uint16_t port) server_address.sin_port = htons(port); #pragma GCC diagnostic pop - if (bind(fd, reinterpret_cast<struct sockaddr *>(&server_address), + if (fd.bind(reinterpret_cast<struct sockaddr *>(&server_address), sizeof(server_address)) == -1) { perror("bind"); exit(1); } - if (listen(fd, 5) == -1) + if (fd.listen(5) == -1) { /* error */ perror("listen"); exit(1); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - session[fd] = make_unique<Session>(); - Session *s = session[fd].get(); + set_session(fd, make_unique<Session>()); + Session *s = get_session(fd); s->fd = fd; s->func_recv = connect_client; @@ -247,25 +268,25 @@ Session *make_listen_port(uint16_t port) Session *make_connection(IP4Address ip, uint16_t port) { struct sockaddr_in server_address; - int fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) + io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0); + if (fd == io::FD()) { perror("socket"); return nullptr; } - if (fd_max <= fd) - fd_max = fd + 1; + if (fd_max <= fd.uncast_dammit()) + fd_max = fd.uncast_dammit() + 1; const int yes = 1; /// Allow to bind() again after the server restarts. // Since the socket is still in the TIME_WAIT, there's a possibility // that formerly lost packets might be delivered and confuse the server. - setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); /// Send packets as soon as possible /// even if the kernel thinks there is too little for it to be worth it! // I'm not convinced this is a good idea; although in minimizes the // latency for an individual write, it increases traffic in general. - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); + fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; server_address.sin_addr = in_addr(ip); @@ -277,20 +298,17 @@ Session *make_connection(IP4Address ip, uint16_t port) server_address.sin_port = htons(port); #pragma GCC diagnostic pop - fcntl(fd, F_SETFL, O_NONBLOCK); + fd.fcntl(F_SETFL, O_NONBLOCK); /// Errors not caught - we must not block /// Let the main select() loop detect when we know the state - connect(fd, reinterpret_cast<struct sockaddr *>(&server_address), + fd.connect(reinterpret_cast<struct sockaddr *>(&server_address), sizeof(struct sockaddr_in)); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(fd, &readfds); -#pragma GCC diagnostic pop + readfds.set(fd); - session[fd] = make_unique<Session>(); - Session *s = session[fd].get(); + set_session(fd, make_unique<Session>()); + Session *s = get_session(fd); s->fd = fd; s->rdata.new_(RFIFO_SIZE); s->wdata.new_(WFIFO_SIZE); @@ -311,26 +329,23 @@ void delete_session(Session *s) if (!s) return; - int fd = s->fd; + io::FD fd = s->fd; // If this was the highest fd, decrease it // We could add a loop to decrement fd_max further for every null session, // but this is cheap and good enough for the typical case - if (fd == fd_max - 1) + if (fd.uncast_dammit() == fd_max - 1) fd_max--; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_CLR(fd, &readfds); -#pragma GCC diagnostic pop + readfds.clr(fd); { s->rdata.delete_(); s->wdata.delete_(); s->session_data.reset(); - session[fd].reset(); + reset_session(fd); } // just close() would try to keep sending buffers - shutdown(fd, SHUT_RDWR); - close(fd); + fd.shutdown(SHUT_RDWR); + fd.close(); } void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) @@ -362,18 +377,12 @@ void WFIFOSET(Session *s, size_t len) void do_sendrecv(interval_t next_ms) { - fd_set rfd = readfds, wfd; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_ZERO(&wfd); -#pragma GCC diagnostic pop - for (int i = 0; i < fd_max; i++) + io::FD_Set rfd = readfds, wfd; + for (io::FD i : iter_fds()) { - if (session[i] && session[i]->wdata_size) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_SET(i, &wfd); -#pragma GCC diagnostic pop + Session *s = get_session(i); + if (s && s->wdata_size) + wfd.set(i); } struct timeval timeout; { @@ -382,26 +391,20 @@ void do_sendrecv(interval_t next_ms) timeout.tv_sec = next_s.count(); timeout.tv_usec = next_us.count(); } - if (select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) + if (io::FD_Set::select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0) return; - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - if (FD_ISSET(i, &wfd)) -#pragma GCC diagnostic pop + if (wfd.isset(i)) { if (s->func_send) //send_from_fifo(i); s->func_send(s); } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - if (FD_ISSET(i, &rfd)) -#pragma GCC diagnostic pop + if (rfd.isset(i)) { if (s->func_recv) //recv_to_fifo(i); @@ -413,15 +416,15 @@ void do_sendrecv(interval_t next_ms) void do_parsepacket(void) { - for (int i = 0; i < fd_max; i++) + for (io::FD i : iter_fds()) { - Session *s = session[i].get(); + Session *s = get_session(i); if (!s) continue; if (!s->connected && static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT) { - PRINTF("Session #%d timed out\n", i); + PRINTF("Session #%d timed out\n", s); s->eof = 1; } if (!s->rdata_size && !s->eof) @@ -438,14 +441,6 @@ void do_parsepacket(void) } } -void do_socket(void) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wold-style-cast" - FD_ZERO(&readfds); -#pragma GCC diagnostic pop -} - void RFIFOSKIP(Session *s, size_t len) { s->rdata_pos += len; diff --git a/src/common/socket.hpp b/src/common/socket.hpp index 4d51604..6d0ca01 100644 --- a/src/common/socket.hpp +++ b/src/common/socket.hpp @@ -13,6 +13,8 @@ # include "../strings/vstring.hpp" # include "../strings/xstring.hpp" +# include "../io/fd.hpp" + # include "dumb_ptr.hpp" # include "ip.hpp" # include "utils.hpp" @@ -64,13 +66,13 @@ struct Session /// Server-specific data type std::unique_ptr<SessionData, SessionDeleter> session_data; - int fd; + io::FD fd; }; inline int convert_for_printf(Session *s) { - return s->fd; + return s->fd.uncast_dammit(); } // save file descriptors for important stuff @@ -79,12 +81,23 @@ constexpr int SOFT_LIMIT = FD_SETSIZE - 50; // socket timeout to establish a full connection in seconds constexpr int CONNECT_TIMEOUT = 15; -/// Everyone who has connected -// note: call delete_session(i) to null out an element -extern std::array<std::unique_ptr<Session>, FD_SETSIZE> session; -/// Maximum used FD, +1 -extern int fd_max; +void set_session(io::FD fd, std::unique_ptr<Session> sess); +Session *get_session(io::FD fd); +void reset_session(io::FD fd); +int get_fd_max(); + +class IncrFD +{ +public: + static + io::FD inced(io::FD v) + { + return io::FD::cast_dammit(v.uncast_dammit() + 1); + } +}; +IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds(); + /// open a socket, bind, and listen. Return an fd, or -1 if socket() fails, /// but exit if bind() or listen() fails @@ -101,9 +114,6 @@ void do_sendrecv(interval_t next); /// Call the parser function for every socket that has read data void do_parsepacket(void); -/// An init function -void do_socket(void); - /// Change the default parser for newly connected clients // typically called once per server, but individual clients may identify // themselves as servers diff --git a/src/common/utils2.hpp b/src/common/utils2.hpp index 0f72aff..ac55a5a 100644 --- a/src/common/utils2.hpp +++ b/src/common/utils2.hpp @@ -9,6 +9,8 @@ # include <memory> # include <type_traits> +# include "iter.hpp" + # ifdef __clang__ # define FALLTHROUGH [[clang::fallthrough]] # else @@ -92,25 +94,6 @@ public: } }; -template<class It> -class IteratorPair -{ - It _b, _e; -public: - IteratorPair(It b, It e) - : _b(b), _e(e) - {} - - It begin() { return _b; } - It end() { return _e; } -}; - -template<class It> -IteratorPair<It> iterator_pair(It b, It e) -{ - return {b, e}; -} - // std::underlying_type isn't supported until gcc 4.7 // this is a poor man's emulation template<class E> @@ -177,41 +160,19 @@ E operator ~ (E r) \ } template<class E> -class EnumValueIterator +class EnumMath { typedef typename underlying_type<E>::type U; - E value; public: - EnumValueIterator(E v) - : value(v) - {} - - E operator *() - { - return value; - } - EnumValueIterator& operator++ () - { - value = E(U(value) + 1); - return *this; - } - EnumValueIterator& operator-- () - { - value = E(U(value) - 1); - return *this; - } - friend bool operator == (EnumValueIterator l, EnumValueIterator r) - { - return l.value == r.value; - } - friend bool operator != (EnumValueIterator l, EnumValueIterator r) + static + E inced(E v) { - return !(l == r); + return E(U(v) + 1); } }; template<class E> -IteratorPair<EnumValueIterator<E>> erange(E b, E e) +IteratorPair<ValueIterator<E, EnumMath<E>>> erange(E b, E e) { return {b, e}; } |