From 41b1fc9371adfe1bbf83ce97f7fd90b7d2aca9bf Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Tue, 13 Aug 2019 21:19:35 -0700 Subject: [PATCH] #565: implement nsASCIIMask from M1358297 --- xpcom/string/moz.build | 2 ++ xpcom/string/nsASCIIMask.cpp | 55 ++++++++++++++++++++++++++++ xpcom/string/nsASCIIMask.h | 70 ++++++++++++++++++++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 xpcom/string/nsASCIIMask.cpp create mode 100644 xpcom/string/nsASCIIMask.h diff --git a/xpcom/string/moz.build b/xpcom/string/moz.build index 62518f3cd..eafbaaa62 100644 --- a/xpcom/string/moz.build +++ b/xpcom/string/moz.build @@ -8,6 +8,7 @@ with Files('**'): BUG_COMPONENT = ('Core', 'String') EXPORTS += [ + 'nsASCIIMask.h', 'nsAString.h', 'nsCharTraits.h', 'nsDependentString.h', @@ -39,6 +40,7 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ + 'nsASCIIMask.cpp', 'nsDependentString.cpp', 'nsDependentSubstring.cpp', 'nsPromiseFlatString.cpp', diff --git a/xpcom/string/nsASCIIMask.cpp b/xpcom/string/nsASCIIMask.cpp new file mode 100644 index 000000000..1c617a5b4 --- /dev/null +++ b/xpcom/string/nsASCIIMask.cpp @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsASCIIMask.h" + +namespace mozilla { + +constexpr bool TestWhitespace(char c) +{ + return c == '\f' || c == '\t' || c == '\r' || c == '\n' || c == ' '; +} +constexpr ASCIIMaskArray sWhitespaceMask = CreateASCIIMask(TestWhitespace); + +constexpr bool TestCRLF(char c) +{ + return c == '\r' || c == '\n'; +} +constexpr ASCIIMaskArray sCRLFMask = CreateASCIIMask(TestCRLF); + +constexpr bool TestCRLFTab(char c) +{ + return c == '\r' || c == '\n' || c == '\t'; +} +constexpr ASCIIMaskArray sCRLFTabMask = CreateASCIIMask(TestCRLFTab); + +constexpr bool TestZeroToNine(char c) +{ + return c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || + c == '5' || c == '6' || c == '7' || c == '8' || c == '9'; +} +constexpr ASCIIMaskArray sZeroToNineMask = CreateASCIIMask(TestZeroToNine); + +const ASCIIMaskArray& ASCIIMask::MaskWhitespace() +{ + return sWhitespaceMask; +} + +const ASCIIMaskArray& ASCIIMask::MaskCRLF() +{ + return sCRLFMask; +} + +const ASCIIMaskArray& ASCIIMask::MaskCRLFTab() +{ + return sCRLFTabMask; +} + +const ASCIIMaskArray& ASCIIMask::Mask0to9() +{ + return sZeroToNineMask; +} + +} // namespace mozilla diff --git a/xpcom/string/nsASCIIMask.h b/xpcom/string/nsASCIIMask.h new file mode 100644 index 000000000..7a3e76bef --- /dev/null +++ b/xpcom/string/nsASCIIMask.h @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsASCIIMask_h_ +#define nsASCIIMask_h_ + +#include +#include "mozilla/IndexSequence.h" + +typedef std::array ASCIIMaskArray; + +namespace mozilla { + +// Boolean arrays, fixed size and filled in at compile time, meant to +// record something about each of the (standard) ASCII characters. +// No extended ASCII for now, there has been no use case. +// If you have loops that go through a string character by character +// and test for equality to a certain set of characters before deciding +// on a course of action, chances are building up one of these arrays +// and using it is going to be faster, especially if the set of +// characters is more than one long, and known at compile time. +class ASCIIMask +{ +public: + // Preset masks for some common character groups + // When testing, you must check if the index is < 128 or use IsMasked() + // + // if (someChar < 128 && MaskCRLF()[someChar]) this is \r or \n + + static const ASCIIMaskArray& MaskCRLF(); + static const ASCIIMaskArray& Mask0to9(); + static const ASCIIMaskArray& MaskCRLFTab(); + static const ASCIIMaskArray& MaskWhitespace(); + + static MOZ_ALWAYS_INLINE bool IsMasked(const ASCIIMaskArray& aMask, uint32_t aChar) + { + return aChar < 128 && aMask[aChar]; + } +}; + +// Outside of the preset ones, use these templates to create more masks. +// +// The example creation will look like this: +// +// constexpr bool TestABC(char c) { return c == 'A' || c == 'B' || c == 'C'; } +// constexpr std::array sABCMask = CreateASCIIMask(TestABC); +// ... +// if (someChar < 128 && sABCMask[someChar]) this is A or B or C + + +namespace details +{ +template +constexpr std::array CreateASCIIMask(F fun, mozilla::IndexSequence) +{ + return {{ fun(Indices)... }}; +} +} // namespace details + +template +constexpr std::array CreateASCIIMask(F fun) +{ + return details::CreateASCIIMask(fun, mozilla::MakeIndexSequence<128>::Type{}); +} + +} // namespace mozilla + +#endif // nsASCIIMask_h_