From 1b1ebdf183e50c6a751493570ee6e643c33c4eda Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 4 Oct 2021 11:48:58 -0400 Subject: SL-16024: Introduce tuple.h with tuple_cons(), tuple_cdr(). These functions allow prepending or removing an item at the left end of an arbitrary tuple -- for instance, to add a sequence key to a caller's data, then remove it again when delivering the original tuple. --- indra/llcommon/tuple.h | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 indra/llcommon/tuple.h (limited to 'indra/llcommon/tuple.h') diff --git a/indra/llcommon/tuple.h b/indra/llcommon/tuple.h new file mode 100644 index 0000000000..bfe7e3c2ba --- /dev/null +++ b/indra/llcommon/tuple.h @@ -0,0 +1,84 @@ +/** + * @file tuple.h + * @author Nat Goodspeed + * @date 2021-10-04 + * @brief A couple tuple utilities + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_TUPLE_H) +#define LL_TUPLE_H + +#include +#include // std::remove_reference +#include // std::pair + +/** + * tuple_cons() behaves like LISP cons: it uses std::tuple_cat() to prepend a + * new item of arbitrary type to an existing std::tuple. + */ +template > +auto tuple_cons(First&& first, Tuple_&& rest) +{ + // All we need to do is make a tuple containing 'first', and let + // tuple_cat() do the hard part. + return std::tuple_cat(std::tuple(std::forward(first)), + std::forward(rest)); +} + +/** + * tuple_car() behaves like LISP car: it extracts the first item from a + * std::tuple. + */ +template > +auto tuple_car(Tuple_&& tuple) +{ + return std::get<0>(std::forward(tuple)); +} + +/** + * tuple_cdr() behaves like LISP cdr: it returns a new tuple containing + * everything BUT the first item. + */ +// derived from https://stackoverflow.com/a/24046437 +template +auto tuple_cdr_(Tuple&& tuple, const std::index_sequence) +{ + // Given an index sequence from [0..N-1), extract tuple items [1..N) + return std::make_tuple(std::get(std::forward(tuple))...); +} + +template +auto tuple_cdr(Tuple&& tuple) +{ + return tuple_cdr_( + std::forward(tuple), + // Pass helper function an index sequence one item shorter than tuple + std::make_index_sequence< + std::tuple_size< + // tuple_size doesn't like reference types + typename std::remove_reference::type + >::value - 1u> + ()); +} + +/** + * tuple_split(), the opposite of tuple_cons(), has no direct analog in LISP. + * It returns a std::pair of tuple_car(), tuple_cdr(). We could call this + * function tuple_car_cdr(), or tuple_slice() or some such. But tuple_split() + * feels more descriptive. + */ +template > +auto tuple_split(Tuple_&& tuple) +{ + // We're not really worried about forwarding multiple times a tuple that + // might contain move-only items, because the implementation above only + // applies std::get() exactly once to each item. + return std::make_pair(tuple_car(std::forward(tuple)), + tuple_cdr(std::forward(tuple))); +} + +#endif /* ! defined(LL_TUPLE_H) */ -- cgit v1.2.3