Bug 1344629 - Part 3: Move const accessors from nsTSubstring to nsTStringRepr. r=dbaron
authorDavid Major <dmajor@mozilla.com>
Tue, 14 Mar 2017 10:02:50 +1300
changeset 347452 485e1632ef228d3dd621c5f4ae297795335a5dc1
parent 347451 271be9871274124c392acab68a972408e3c99be5
child 347453 e7bf771e880277cd09e761094b2ff0e745505b74
push id31496
push usercbook@mozilla.com
push dateTue, 14 Mar 2017 13:21:57 +0000
treeherdermozilla-central@9a26ed658fdc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1344629
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1344629 - Part 3: Move const accessors from nsTSubstring to nsTStringRepr. r=dbaron All nsTStringRepr methods must be const, so the mutators remain on nsTSubstring. I left a small number of const methods on nsTSubstring, e.g. Capacity(), the rationale being that you would only be interested in this method if you intend to mutate the string. I considered splitting up the typedefs block and leaving behind the ones related to mutation (e.g. nsWritingIterator) but I think it makes for clearer documentation to have them all in one place. MozReview-Commit-ID: 7dEaRgc8NLK
xpcom/string/nsStringFwd.h
xpcom/string/nsStringIterator.h
xpcom/string/nsTSubstring.cpp
xpcom/string/nsTSubstring.h
--- a/xpcom/string/nsStringFwd.h
+++ b/xpcom/string/nsStringFwd.h
@@ -10,16 +10,25 @@
 #define nsStringFwd_h___
 
 #include "nscore.h"
 
 #ifndef MOZILLA_INTERNAL_API
 #error Internal string headers are not available from external-linkage code.
 #endif
 
+namespace mozilla {
+namespace detail {
+
+class nsStringRepr;
+class nsCStringRepr;
+
+} // namespace detail
+} // namespace mozilla
+
 /**
  * double-byte (char16_t) string types
  */
 
 class nsAString;
 class nsSubstringTuple;
 class nsString;
 class nsAutoString;
--- a/xpcom/string/nsStringIterator.h
+++ b/xpcom/string/nsStringIterator.h
@@ -22,18 +22,18 @@ public:
   typedef nsReadingIterator<CharT>    self_type;
   typedef ptrdiff_t                   difference_type;
   typedef size_t                      size_type;
   typedef CharT                       value_type;
   typedef const CharT*                pointer;
   typedef const CharT&                reference;
 
 private:
-  friend class nsAString;
-  friend class nsACString;
+  friend class mozilla::detail::nsStringRepr;
+  friend class mozilla::detail::nsCStringRepr;
 
   // unfortunately, the API for nsReadingIterator requires that the
   // iterator know its start and end positions.  this was needed when
   // we supported multi-fragment strings, but now it is really just
   // extra baggage.  we should remove mStart and mEnd at some point.
 
   const CharT* mStart;
   const CharT* mEnd;
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -27,31 +27,16 @@ nsTSubstring_CharT::nsTSubstring_CharT(c
  * helper function for down-casting a nsTSubstring to a nsTFixedString.
  */
 inline const nsTFixedString_CharT*
 AsFixedString(const nsTSubstring_CharT* aStr)
 {
   return static_cast<const nsTFixedString_CharT*>(aStr);
 }
 
-
-nsTSubstring_CharT::char_type
-nsTSubstring_CharT::First() const
-{
-  MOZ_RELEASE_ASSERT(mLength > 0, "|First()| called on an empty string");
-  return mData[0];
-}
-
-nsTSubstring_CharT::char_type
-nsTSubstring_CharT::Last() const
-{
-  MOZ_RELEASE_ASSERT(mLength > 0, "|Last()| called on an empty string");
-  return mData[mLength - 1];
-}
-
 /**
  * this function is called to prepare mData for writing.  the given capacity
  * indicates the required minimum storage size for mData, in sizeof(char_type)
  * increments.  this function returns true if the operation succeeds.  it also
  * returns the old data and old flags members if mData is newly allocated.
  * the old data must be released by the caller.
  */
 bool
@@ -757,112 +742,132 @@ nsTSubstring_CharT::SetIsVoid(bool aVal)
   if (aVal) {
     Truncate();
     mFlags |= F_VOIDED;
   } else {
     mFlags &= ~F_VOIDED;
   }
 }
 
+namespace mozilla {
+namespace detail {
+
+nsTStringRepr_CharT::char_type
+nsTStringRepr_CharT::First() const
+{
+  MOZ_RELEASE_ASSERT(mLength > 0, "|First()| called on an empty string");
+  return mData[0];
+}
+
+nsTStringRepr_CharT::char_type
+nsTStringRepr_CharT::Last() const
+{
+  MOZ_RELEASE_ASSERT(mLength > 0, "|Last()| called on an empty string");
+  return mData[mLength - 1];
+}
+
 bool
-nsTSubstring_CharT::Equals(const self_type& aStr) const
+nsTStringRepr_CharT::Equals(const self_type& aStr) const
 {
   return mLength == aStr.mLength &&
          char_traits::compare(mData, aStr.mData, mLength) == 0;
 }
 
 bool
-nsTSubstring_CharT::Equals(const self_type& aStr,
-                           const comparator_type& aComp) const
+nsTStringRepr_CharT::Equals(const self_type& aStr,
+                            const comparator_type& aComp) const
 {
   return mLength == aStr.mLength &&
          aComp(mData, aStr.mData, mLength, aStr.mLength) == 0;
 }
 
 bool
-nsTSubstring_CharT::Equals(const char_type* aData) const
+nsTStringRepr_CharT::Equals(const char_type* aData) const
 {
   // unfortunately, some callers pass null :-(
   if (!aData) {
     NS_NOTREACHED("null data pointer");
     return mLength == 0;
   }
 
   // XXX avoid length calculation?
   size_type length = char_traits::length(aData);
   return mLength == length &&
          char_traits::compare(mData, aData, mLength) == 0;
 }
 
 bool
-nsTSubstring_CharT::Equals(const char_type* aData,
-                           const comparator_type& aComp) const
+nsTStringRepr_CharT::Equals(const char_type* aData,
+                            const comparator_type& aComp) const
 {
   // unfortunately, some callers pass null :-(
   if (!aData) {
     NS_NOTREACHED("null data pointer");
     return mLength == 0;
   }
 
   // XXX avoid length calculation?
   size_type length = char_traits::length(aData);
   return mLength == length && aComp(mData, aData, mLength, length) == 0;
 }
 
 bool
-nsTSubstring_CharT::EqualsASCII(const char* aData, size_type aLen) const
+nsTStringRepr_CharT::EqualsASCII(const char* aData, size_type aLen) const
 {
   return mLength == aLen &&
          char_traits::compareASCII(mData, aData, aLen) == 0;
 }
 
 bool
-nsTSubstring_CharT::EqualsASCII(const char* aData) const
+nsTStringRepr_CharT::EqualsASCII(const char* aData) const
 {
   return char_traits::compareASCIINullTerminated(mData, mLength, aData) == 0;
 }
 
 bool
-nsTSubstring_CharT::LowerCaseEqualsASCII(const char* aData,
-                                         size_type aLen) const
+nsTStringRepr_CharT::LowerCaseEqualsASCII(const char* aData,
+                                          size_type aLen) const
 {
   return mLength == aLen &&
          char_traits::compareLowerCaseToASCII(mData, aData, aLen) == 0;
 }
 
 bool
-nsTSubstring_CharT::LowerCaseEqualsASCII(const char* aData) const
+nsTStringRepr_CharT::LowerCaseEqualsASCII(const char* aData) const
 {
   return char_traits::compareLowerCaseToASCIINullTerminated(mData,
                                                             mLength,
                                                             aData) == 0;
 }
 
-nsTSubstring_CharT::size_type
-nsTSubstring_CharT::CountChar(char_type aChar) const
+nsTStringRepr_CharT::size_type
+nsTStringRepr_CharT::CountChar(char_type aChar) const
 {
   const char_type* start = mData;
   const char_type* end   = mData + mLength;
 
   return NS_COUNT(start, end, aChar);
 }
 
 int32_t
-nsTSubstring_CharT::FindChar(char_type aChar, index_type aOffset) const
+nsTStringRepr_CharT::FindChar(char_type aChar, index_type aOffset) const
 {
   if (aOffset < mLength) {
     const char_type* result = char_traits::find(mData + aOffset,
                                                 mLength - aOffset, aChar);
     if (result) {
       return result - mData;
     }
   }
   return -1;
 }
 
+} // namespace detail
+} // namespace mozilla
+
 void
 nsTSubstring_CharT::StripChar(char_type aChar, int32_t aOffset)
 {
   if (mLength == 0 || aOffset >= int32_t(mLength)) {
     return;
   }
 
   if (!EnsureMutable()) { // XXX do this lazily?
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -68,83 +68,40 @@ namespace detail {
  * NAMES:
  *   nsStringRepr for wide characters
  *   nsCStringRepr for narrow characters
  *
  */
 class nsTStringRepr_CharT
 {
 public:
-  typedef CharT                               char_type;
-
-  typedef uint32_t                            size_type;
-
-protected:
-  nsTStringRepr_CharT() = delete; // Never instantiate directly
-
-  constexpr
-  nsTStringRepr_CharT(char_type* aData, size_type aLength, uint32_t aFlags)
-    : mData(aData)
-    , mLength(aLength)
-    , mFlags(aFlags)
-  {
-  }
-
-  char_type*  mData;
-  size_type   mLength;
-  uint32_t    mFlags;
-};
+  typedef mozilla::fallible_t                 fallible_t;
 
-} // namespace detail
-} // namespace mozilla
-
-/**
- * nsTSubstring is an abstract string class. From an API perspective, this
- * class is the root of the string class hierarchy. It represents a single
- * contiguous array of characters, which may or may not be null-terminated.
- * This type is not instantiated directly. A sub-class is instantiated
- * instead. For example, see nsTString.
- *
- * NAMES:
- *   nsAString for wide characters
- *   nsACString for narrow characters
- *
- */
-class nsTSubstring_CharT : public mozilla::detail::nsTStringRepr_CharT
-{
-public:
-  typedef mozilla::fallible_t                 fallible_t;
+  typedef CharT                               char_type;
 
   typedef nsCharTraits<char_type>             char_traits;
   typedef char_traits::incompatible_char_type incompatible_char_type;
 
-  typedef nsTSubstring_CharT                  self_type;
+  typedef nsTStringRepr_CharT                 self_type;
   typedef self_type                           base_string_type;
 
-  typedef self_type                           substring_type;
+  typedef nsTSubstring_CharT                  substring_type;
   typedef nsTSubstringTuple_CharT             substring_tuple_type;
   typedef nsTString_CharT                     string_type;
 
   typedef nsReadingIterator<char_type>        const_iterator;
   typedef nsWritingIterator<char_type>        iterator;
 
   typedef nsTStringComparator_CharT           comparator_type;
 
   typedef char_type*                          char_iterator;
   typedef const char_type*                    const_char_iterator;
 
   typedef uint32_t                            index_type;
-
-public:
-
-  // this acts like a virtual destructor
-  ~nsTSubstring_CharT()
-  {
-    Finalize();
-  }
+  typedef uint32_t                            size_type;
 
   /**
    * reading iterators
    */
 
   const_char_iterator BeginReading() const
   {
     return mData;
@@ -179,91 +136,16 @@ public:
     return aIter = mData;
   }
 
   const_char_iterator& EndReading(const_char_iterator& aIter) const
   {
     return aIter = mData + mLength;
   }
 
-
-  /**
-   * writing iterators
-   */
-
-  char_iterator BeginWriting()
-  {
-    if (!EnsureMutable()) {
-      AllocFailed(mLength);
-    }
-
-    return mData;
-  }
-
-  char_iterator BeginWriting(const fallible_t&)
-  {
-    return EnsureMutable() ? mData : char_iterator(0);
-  }
-
-  char_iterator EndWriting()
-  {
-    if (!EnsureMutable()) {
-      AllocFailed(mLength);
-    }
-
-    return mData + mLength;
-  }
-
-  char_iterator EndWriting(const fallible_t&)
-  {
-    return EnsureMutable() ? (mData + mLength) : char_iterator(0);
-  }
-
-  char_iterator& BeginWriting(char_iterator& aIter)
-  {
-    return aIter = BeginWriting();
-  }
-
-  char_iterator& BeginWriting(char_iterator& aIter, const fallible_t& aFallible)
-  {
-    return aIter = BeginWriting(aFallible);
-  }
-
-  char_iterator& EndWriting(char_iterator& aIter)
-  {
-    return aIter = EndWriting();
-  }
-
-  char_iterator& EndWriting(char_iterator& aIter, const fallible_t& aFallible)
-  {
-    return aIter = EndWriting(aFallible);
-  }
-
-  /**
-   * deprecated writing iterators
-   */
-
-  iterator& BeginWriting(iterator& aIter)
-  {
-    char_type* data = BeginWriting();
-    aIter.mStart = data;
-    aIter.mEnd = data + mLength;
-    aIter.mPosition = aIter.mStart;
-    return aIter;
-  }
-
-  iterator& EndWriting(iterator& aIter)
-  {
-    char_type* data = BeginWriting();
-    aIter.mStart = data;
-    aIter.mEnd = data + mLength;
-    aIter.mPosition = aIter.mEnd;
-    return aIter;
-  }
-
   /**
    * accessors
    */
 
   // returns pointer to string data (not necessarily null-terminated)
 #if defined(CharT_is_PRUnichar) && defined(MOZ_USE_CHAR16_WRAPPER)
   char16ptr_t Data() const
 #else
@@ -390,16 +272,205 @@ public:
   // LowerCaseEqualsASCII for them.
   template<int N>
   inline bool LowerCaseEqualsLiteral(const char (&aStr)[N]) const
   {
     return LowerCaseEqualsASCII(aStr, N - 1);
   }
 
   /**
+   * returns true if this string overlaps with the given string fragment.
+   */
+  bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const
+  {
+    /**
+     * if it _isn't_ the case that one fragment starts after the other ends,
+     * or ends before the other starts, then, they conflict:
+     *
+     *   !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin)
+     *
+     * Simplified, that gives us:
+     */
+    return (aStart < (mData + mLength) && aEnd > mData);
+  }
+
+protected:
+  nsTStringRepr_CharT() = delete; // Never instantiate directly
+
+  constexpr
+  nsTStringRepr_CharT(char_type* aData, size_type aLength, uint32_t aFlags)
+    : mData(aData)
+    , mLength(aLength)
+    , mFlags(aFlags)
+  {
+  }
+
+  char_type*  mData;
+  size_type   mLength;
+  uint32_t    mFlags;
+
+public:
+  // mFlags is a bitwise combination of the following flags.  the meaning
+  // and interpretation of these flags is an implementation detail.
+  //
+  // NOTE: these flags are declared public _only_ for convenience inside
+  // the string implementation.
+
+  enum
+  {
+    F_NONE         = 0,       // no flags
+
+    // data flags are in the lower 16-bits
+    F_TERMINATED   = 1 << 0,  // IsTerminated returns true
+    F_VOIDED       = 1 << 1,  // IsVoid returns true
+    F_SHARED       = 1 << 2,  // mData points to a heap-allocated, shared buffer
+    F_OWNED        = 1 << 3,  // mData points to a heap-allocated, raw buffer
+    F_FIXED        = 1 << 4,  // mData points to a fixed-size writable, dependent buffer
+    F_LITERAL      = 1 << 5,  // mData points to a string literal; F_TERMINATED will also be set
+
+    // class flags are in the upper 16-bits
+    F_CLASS_FIXED  = 1 << 16   // indicates that |this| is of type nsTFixedString
+  };
+
+  //
+  // Some terminology:
+  //
+  //   "dependent buffer"    A dependent buffer is one that the string class
+  //                         does not own.  The string class relies on some
+  //                         external code to ensure the lifetime of the
+  //                         dependent buffer.
+  //
+  //   "shared buffer"       A shared buffer is one that the string class
+  //                         allocates.  When it allocates a shared string
+  //                         buffer, it allocates some additional space at
+  //                         the beginning of the buffer for additional
+  //                         fields, including a reference count and a
+  //                         buffer length.  See nsStringHeader.
+  //
+  //   "adopted buffer"      An adopted buffer is a raw string buffer
+  //                         allocated on the heap (using moz_xmalloc)
+  //                         of which the string class subsumes ownership.
+  //
+  // Some comments about the string flags:
+  //
+  //   F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive.  They
+  //   indicate the allocation type of mData.  If none of these flags
+  //   are set, then the string buffer is dependent.
+  //
+  //   F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED.  This is because
+  //   the string classes always allocate null-terminated buffers, and
+  //   non-terminated substrings are always dependent.
+  //
+  //   F_VOIDED implies F_TERMINATED, and moreover it implies that mData
+  //   points to char_traits::sEmptyBuffer.  Therefore, F_VOIDED is
+  //   mutually exclusive with F_SHARED, F_OWNED, and F_FIXED.
+  //
+};
+
+} // namespace detail
+} // namespace mozilla
+
+/**
+ * nsTSubstring is an abstract string class. From an API perspective, this
+ * class is the root of the string class hierarchy. It represents a single
+ * contiguous array of characters, which may or may not be null-terminated.
+ * This type is not instantiated directly. A sub-class is instantiated
+ * instead. For example, see nsTString.
+ *
+ * NAMES:
+ *   nsAString for wide characters
+ *   nsACString for narrow characters
+ *
+ */
+class nsTSubstring_CharT : public mozilla::detail::nsTStringRepr_CharT
+{
+public:
+  typedef nsTSubstring_CharT                  self_type;
+
+  // this acts like a virtual destructor
+  ~nsTSubstring_CharT()
+  {
+    Finalize();
+  }
+
+  /**
+   * writing iterators
+   */
+
+  char_iterator BeginWriting()
+  {
+    if (!EnsureMutable()) {
+      AllocFailed(mLength);
+    }
+
+    return mData;
+  }
+
+  char_iterator BeginWriting(const fallible_t&)
+  {
+    return EnsureMutable() ? mData : char_iterator(0);
+  }
+
+  char_iterator EndWriting()
+  {
+    if (!EnsureMutable()) {
+      AllocFailed(mLength);
+    }
+
+    return mData + mLength;
+  }
+
+  char_iterator EndWriting(const fallible_t&)
+  {
+    return EnsureMutable() ? (mData + mLength) : char_iterator(0);
+  }
+
+  char_iterator& BeginWriting(char_iterator& aIter)
+  {
+    return aIter = BeginWriting();
+  }
+
+  char_iterator& BeginWriting(char_iterator& aIter, const fallible_t& aFallible)
+  {
+    return aIter = BeginWriting(aFallible);
+  }
+
+  char_iterator& EndWriting(char_iterator& aIter)
+  {
+    return aIter = EndWriting();
+  }
+
+  char_iterator& EndWriting(char_iterator& aIter, const fallible_t& aFallible)
+  {
+    return aIter = EndWriting(aFallible);
+  }
+
+  /**
+   * deprecated writing iterators
+   */
+
+  iterator& BeginWriting(iterator& aIter)
+  {
+    char_type* data = BeginWriting();
+    aIter.mStart = data;
+    aIter.mEnd = data + mLength;
+    aIter.mPosition = aIter.mStart;
+    return aIter;
+  }
+
+  iterator& EndWriting(iterator& aIter)
+  {
+    char_type* data = BeginWriting();
+    aIter.mStart = data;
+    aIter.mEnd = data + mLength;
+    aIter.mPosition = aIter.mEnd;
+    return aIter;
+  }
+
+  /**
    * assignment
    */
 
   void NS_FASTCALL Assign(char_type aChar);
   MOZ_MUST_USE bool NS_FASTCALL Assign(char_type aChar, const fallible_t&);
 
   void NS_FASTCALL Assign(const char_type* aData);
   MOZ_MUST_USE bool NS_FASTCALL Assign(const char_type* aData,
@@ -1031,104 +1102,32 @@ protected:
   /**
    * this helper function can be called prior to directly manipulating
    * the contents of mData.  see, for example, BeginWriting.
    */
   MOZ_MUST_USE bool NS_FASTCALL EnsureMutable(
     size_type aNewLen = size_type(-1));
 
   /**
-   * returns true if this string overlaps with the given string fragment.
-   */
-  bool IsDependentOn(const char_type* aStart, const char_type* aEnd) const
-  {
-    /**
-     * if it _isn't_ the case that one fragment starts after the other ends,
-     * or ends before the other starts, then, they conflict:
-     *
-     *   !(f2.begin >= f1.aEnd || f2.aEnd <= f1.begin)
-     *
-     * Simplified, that gives us:
-     */
-    return (aStart < (mData + mLength) && aEnd > mData);
-  }
-
-  /**
    * this helper function stores the specified dataFlags in mFlags
    */
   void SetDataFlags(uint32_t aDataFlags)
   {
     NS_ASSERTION((aDataFlags & 0xFFFF0000) == 0, "bad flags");
     mFlags = aDataFlags | (mFlags & 0xFFFF0000);
   }
 
   void NS_FASTCALL ReplaceLiteral(index_type aCutStart, size_type aCutLength,
                                   const char_type* aData, size_type aLength);
 
 public:
 
   // NOTE: this method is declared public _only_ for convenience for
   // callers who don't have access to the original nsLiteralString_CharT.
   void NS_FASTCALL AssignLiteral(const char_type* aData, size_type aLength);
-
-  // mFlags is a bitwise combination of the following flags.  the meaning
-  // and interpretation of these flags is an implementation detail.
-  //
-  // NOTE: these flags are declared public _only_ for convenience inside
-  // the string implementation.
-
-  enum
-  {
-    F_NONE         = 0,       // no flags
-
-    // data flags are in the lower 16-bits
-    F_TERMINATED   = 1 << 0,  // IsTerminated returns true
-    F_VOIDED       = 1 << 1,  // IsVoid returns true
-    F_SHARED       = 1 << 2,  // mData points to a heap-allocated, shared buffer
-    F_OWNED        = 1 << 3,  // mData points to a heap-allocated, raw buffer
-    F_FIXED        = 1 << 4,  // mData points to a fixed-size writable, dependent buffer
-    F_LITERAL      = 1 << 5,  // mData points to a string literal; F_TERMINATED will also be set
-
-    // class flags are in the upper 16-bits
-    F_CLASS_FIXED  = 1 << 16   // indicates that |this| is of type nsTFixedString
-  };
-
-  //
-  // Some terminology:
-  //
-  //   "dependent buffer"    A dependent buffer is one that the string class
-  //                         does not own.  The string class relies on some
-  //                         external code to ensure the lifetime of the
-  //                         dependent buffer.
-  //
-  //   "shared buffer"       A shared buffer is one that the string class
-  //                         allocates.  When it allocates a shared string
-  //                         buffer, it allocates some additional space at
-  //                         the beginning of the buffer for additional
-  //                         fields, including a reference count and a
-  //                         buffer length.  See nsStringHeader.
-  //
-  //   "adopted buffer"      An adopted buffer is a raw string buffer
-  //                         allocated on the heap (using moz_xmalloc)
-  //                         of which the string class subsumes ownership.
-  //
-  // Some comments about the string flags:
-  //
-  //   F_SHARED, F_OWNED, and F_FIXED are all mutually exlusive.  They
-  //   indicate the allocation type of mData.  If none of these flags
-  //   are set, then the string buffer is dependent.
-  //
-  //   F_SHARED, F_OWNED, or F_FIXED imply F_TERMINATED.  This is because
-  //   the string classes always allocate null-terminated buffers, and
-  //   non-terminated substrings are always dependent.
-  //
-  //   F_VOIDED implies F_TERMINATED, and moreover it implies that mData
-  //   points to char_traits::sEmptyBuffer.  Therefore, F_VOIDED is
-  //   mutually exclusive with F_SHARED, F_OWNED, and F_FIXED.
-  //
 };
 
 static_assert(sizeof(nsTSubstring_CharT) ==
               sizeof(mozilla::detail::nsTStringRepr_CharT),
               "Don't add new data fields to nsTSubstring_CharT. "
               "Add to nsTStringRepr_CharT instead.");
 
 int NS_FASTCALL