[llvm] r228629 - ADT: Allow up to 18 arguments in hash_combine()

Duncan P. N. Exon Smith dexonsmith at apple.com
Mon Feb 9 15:21:06 PST 2015


Author: dexonsmith
Date: Mon Feb  9 17:21:05 2015
New Revision: 228629

URL: http://llvm.org/viewvc/llvm-project?rev=228629&view=rev
Log:
ADT: Allow up to 18 arguments in hash_combine()

I just realized that the specialized metadata node patch I'm about to
commit won't compile on old compilers.  Bump `hash_combine()`'s support
for non-variadic templates to 18 (I tested this by reversing the logic
in the #ifdef).

Modified:
    llvm/trunk/include/llvm/ADT/Hashing.h
    llvm/trunk/unittests/ADT/HashingTest.cpp

Modified: llvm/trunk/include/llvm/ADT/Hashing.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Hashing.h?rev=228629&r1=228628&r2=228629&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Hashing.h (original)
+++ llvm/trunk/include/llvm/ADT/Hashing.h Mon Feb  9 17:21:05 2015
@@ -573,6 +573,171 @@ public:
   // documentation.
 
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13, typename T14,
+            typename T15, typename T16, typename T17, typename T18>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                    const T16 &arg16, const T17 &arg17, const T18 &arg18) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15,
+                   arg16, arg17, arg18);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13, typename T14,
+            typename T15, typename T16, typename T17>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                    const T16 &arg16, const T17 &arg17) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15,
+                   arg16, arg17);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13, typename T14,
+            typename T15, typename T16>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                    const T16 &arg16) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15,
+                   arg16);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13, typename T14,
+            typename T15>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13, const T14 &arg14, const T15 &arg15) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13, typename T14>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13, const T14 &arg14) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12, typename T13>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                    const T13 &arg13) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12, arg13);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11, typename T12>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11, const T12 &arg12) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11, arg12);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10,
+            typename T11>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10, const T11 &arg11) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10, arg11);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9, typename T10>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                    const T10 &arg10) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9, arg10);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8, typename T9>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8, const T9 &arg9) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8, arg9);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7, typename T8>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7, const T8 &arg8) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7, arg8);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
+            typename T6, typename T7>
+  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
+                    const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                    const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                    const T7 &arg7) {
+    buffer_ptr =
+        combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg1));
+    return combine(length, buffer_ptr, buffer_end, arg2, arg3, arg4, arg5, arg6,
+                   arg7);
+  }
+  template <typename T1, typename T2, typename T3, typename T4, typename T5,
             typename T6>
   hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
                     const T1 &arg1, const T2 &arg2, const T3 &arg3,
@@ -669,6 +834,150 @@ template <typename ...Ts> hash_code hash
 // the above variadic definition for documentation and specification.
 
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13, typename T14, typename T15,
+          typename T16, typename T17, typename T18>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                       const T16 &arg16, const T17 &arg17, const T18 &arg18) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13, arg14, arg15, arg16, arg17, arg18);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13, typename T14, typename T15,
+          typename T16, typename T17>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                       const T16 &arg16, const T17 &arg17) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13, arg14, arg15, arg16, arg17);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13, typename T14, typename T15,
+          typename T16>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13, const T14 &arg14, const T15 &arg15,
+                       const T16 &arg16) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13, arg14, arg15, arg16);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13, typename T14, typename T15>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13, const T14 &arg14, const T15 &arg15) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13, arg14, arg15);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13, typename T14>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13, const T14 &arg14) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13, arg14);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12, typename T13>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12,
+                       const T13 &arg13) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12,
+                        arg13);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11, typename T12>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11, const T12 &arg12) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11,
+                        arg12);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10,
+          typename T11>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10, const T11 &arg11) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9, typename T10>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9,
+                       const T10 &arg10) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9, arg10);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8, typename T9>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8, const T9 &arg9) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8, arg9);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7, typename T8>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7, const T8 &arg8) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7, arg8);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+          typename T6, typename T7>
+hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
+                       const T4 &arg4, const T5 &arg5, const T6 &arg6,
+                       const T7 &arg7) {
+  ::llvm::hashing::detail::hash_combine_recursive_helper helper;
+  return helper.combine(0, helper.buffer, helper.buffer + 64, arg1, arg2, arg3,
+                        arg4, arg5, arg6, arg7);
+}
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
           typename T6>
 hash_code hash_combine(const T1 &arg1, const T2 &arg2, const T3 &arg3,
                        const T4 &arg4, const T5 &arg5, const T6 &arg6) {

Modified: llvm/trunk/unittests/ADT/HashingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/HashingTest.cpp?rev=228629&r1=228628&r2=228629&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/HashingTest.cpp (original)
+++ llvm/trunk/unittests/ADT/HashingTest.cpp Mon Feb  9 17:21:05 2015
@@ -421,4 +421,29 @@ TEST(HashingTest, HashCombineBasicTest)
             hash_combine(bigarr[0], l2, bigarr[9], l3, bigarr[18], bigarr[19]));
 }
 
+TEST(HashingTest, HashCombineArgs18) {
+  // This tests that we can pass in up to 18 args.
+#define CHECK_SAME(...)                                                        \
+  EXPECT_EQ(hash_combine(__VA_ARGS__), hash_combine(__VA_ARGS__))
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8, 9);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7, 8);
+  CHECK_SAME(1, 2, 3, 4, 5, 6, 7);
+  CHECK_SAME(1, 2, 3, 4, 5, 6);
+  CHECK_SAME(1, 2, 3, 4, 5);
+  CHECK_SAME(1, 2, 3, 4);
+  CHECK_SAME(1, 2, 3);
+  CHECK_SAME(1, 2);
+  CHECK_SAME(1);
+#undef CHECK_SAME
+}
+
 }





More information about the llvm-commits mailing list