1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Javascript: Update choc dependency

This fixes an issue when evaluating javascript on macOS while address sanitiser
and undefined behaviour sanitiser are both enabled
This commit is contained in:
Anthony Nicholls 2024-10-28 10:11:44 +00:00
parent b108fe26c3
commit 24d33759b8
39 changed files with 564 additions and 484 deletions

View file

@ -1,12 +0,0 @@
The files in this directory were downloaded from the choc repository at
https://github.com/Tracktion/choc.
In order to avoid exposing any symbols in the choc implementation, the files were modified by
prepending all `namespace choc...` lines with `namespace {`, and by adding corresponding closing
brackets as well.
Enclosing all choc definitions in an anonymous namespace allows JUCE based projects to use an
external copy of choc without running into multiply defined symbol compilation errors.
By placing the anonymous namespace encapsulation inside the choc header files we avoid the issue of
including the system headers in the namespace as well.

View file

@ -27,8 +27,6 @@
#include <exception>
#include "../platform/choc_Assert.h"
namespace
{
namespace choc::value
{
@ -430,19 +428,36 @@ public:
//==============================================================================
/** A simple implementation of StringDictionary.
This should have good performance for typical-sized dictionaries.
Adding new strings will require O(n) time where n = dictionary size, but
Adding new strings will require O(log n) time where n = dictionary size, but
retrieving the string for a handle is fast with O(1).
*/
struct SimpleStringDictionary : public StringDictionary
{
SimpleStringDictionary() = default;
SimpleStringDictionary (const SimpleStringDictionary& other) : strings (other.strings), stringMap (other.stringMap) {}
SimpleStringDictionary (SimpleStringDictionary&& other) : strings (std::move (other.strings)), stringMap (std::move (other.stringMap)) {}
SimpleStringDictionary& operator= (const SimpleStringDictionary& other) { strings = other.strings; stringMap = other.stringMap; return *this; }
SimpleStringDictionary& operator= (SimpleStringDictionary&& other) { strings = std::move (other.strings); stringMap = std::move (other.stringMap); return *this; }
Handle getHandleForString (std::string_view) override;
std::string_view getStringForHandle (Handle handle) const override;
bool empty() const { return strings.empty(); }
void clear();
size_t getRawDataSize() const { return strings.size(); }
const char* getRawData() const { return strings.data(); }
void setRawData (const void*, size_t);
private:
std::pair<std::vector<uint32_t>::const_iterator, bool> findGreaterThanOrEqual (std::string_view) const;
/// The strings are stored in a single chunk, which can be saved and
/// reloaded if necessary.
/// reloaded if necessary. The stringMap is a sorted vector of handles
/// supporting fast lookup of strings in the map
std::vector<char> strings;
std::vector<uint32_t> stringMap;
};
//==============================================================================
@ -1654,15 +1669,17 @@ inline int Type::getObjectMemberIndex (std::string_view name) const
template <typename PrimitiveType>
inline constexpr Type::MainType Type::selectMainType()
{
if constexpr (std::is_same<const PrimitiveType, const int32_t>::value) return MainType::int32;
if constexpr (std::is_same<const PrimitiveType, const int64_t>::value) return MainType::int64;
if constexpr (std::is_same<const PrimitiveType, const float>::value) return MainType::float32;
if constexpr (std::is_same<const PrimitiveType, const double>::value) return MainType::float64;
if constexpr (std::is_same<const PrimitiveType, const bool>::value) return MainType::boolean;
if constexpr (std::is_same<const PrimitiveType, const char* const>::value) return MainType::string;
if constexpr (std::is_same<const PrimitiveType, const std::string>::value) return MainType::string;
Type::MainType result = MainType::void_;
return MainType::void_;
if constexpr (std::is_same<const PrimitiveType, const int32_t>::value) result = MainType::int32;
else if constexpr (std::is_same<const PrimitiveType, const int64_t>::value) result = MainType::int64;
else if constexpr (std::is_same<const PrimitiveType, const float>::value) result = MainType::float32;
else if constexpr (std::is_same<const PrimitiveType, const double>::value) result = MainType::float64;
else if constexpr (std::is_same<const PrimitiveType, const bool>::value) result = MainType::boolean;
else if constexpr (std::is_same<const PrimitiveType, const char* const>::value) result = MainType::string;
else if constexpr (std::is_same<const PrimitiveType, const std::string>::value) result = MainType::string;
return result;
}
template <typename PrimitiveType>
@ -2302,7 +2319,11 @@ inline StringDictionary::Handle ValueView::getStringHandle() const
inline std::string_view ValueView::getString() const
{
check (stringDictionary != nullptr, "No string dictionary supplied");
// To satisfy the MSVC code analyser this check needs to be handled directly
// from this function
if (stringDictionary == nullptr)
throwError ("No string dictionary supplied");
return stringDictionary->getStringForHandle (getStringHandle());
}
@ -2409,21 +2430,43 @@ void ValueView::serialise (OutputStream& output) const
if (type.isVoid())
return;
auto dataSize = type.getValueDataSize();
auto dataSize = type.getValueDataSize();
check (dataSize > 0, "Invalid data size");
if (stringDictionary == nullptr || ! type.usesStrings())
{
output.write (data, dataSize);
return;
}
if (stringDictionary == nullptr || ! type.usesStrings())
{
output.write (data, dataSize);
return;
}
static constexpr uint32_t maximumSize = 16384;
uint8_t* localCopy = nullptr;
if (dataSize > maximumSize)
throwError ("Out of local scratch space");
#if _MSC_VER
uint8_t localCopy[maximumSize];
std::memcpy (localCopy, data, dataSize);
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
#endif
__try
{
localCopy = (uint8_t*) _alloca (dataSize);
}
__except (GetExceptionCode() == STATUS_STACK_OVERFLOW)
{
throwError ("Stack overflow");
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#else
localCopy = (uint8_t*) alloca (dataSize);
#endif
check (localCopy != nullptr, "Stack allocation failed");
std::memcpy (localCopy, data, dataSize);
static constexpr uint32_t maxStrings = 128;
uint32_t numStrings = 0, stringDataSize = 0;
@ -2918,11 +2961,10 @@ template <typename OutputStream> void Value::serialise (OutputStream& o) const
{
o.write (getRawData(), value.type.getValueDataSize());
if (auto stringDataSize = static_cast<uint32_t> (dictionary.strings.size()))
if (auto stringDataSize = static_cast<uint32_t> (dictionary.getRawDataSize()))
{
CHOC_ASSERT (dictionary.strings.back() == 0);
Type::SerialisationHelpers::writeVariableLengthInt (o, stringDataSize);
o.write (dictionary.strings.data(), stringDataSize);
o.write (dictionary.getRawData(), stringDataSize);
}
}
}
@ -2947,9 +2989,7 @@ inline Value Value::deserialise (InputData& input)
{
auto stringDataSize = Type::SerialisationHelpers::readVariableLengthInt (input);
Type::SerialisationHelpers::expect (stringDataSize <= static_cast<uint32_t> (input.end - input.start));
v.dictionary.strings.resize (stringDataSize);
std::memcpy (v.dictionary.strings.data(), input.start, stringDataSize);
Type::SerialisationHelpers::expect (v.dictionary.strings.back() == 0);
v.dictionary.setRawData (input.start, stringDataSize);
}
return v;
@ -3207,20 +3247,20 @@ inline SimpleStringDictionary::Handle SimpleStringDictionary::getHandleForString
if (text.empty())
return {};
for (size_t i = 0; i < strings.size(); ++i)
{
std::string_view sv (strings.data() + i);
auto i = findGreaterThanOrEqual (text);
if (text == sv)
return { static_cast<decltype(Handle::handle)> (i + 1) };
i += sv.length();
}
if (i.second)
return { *i.first };
auto newHandle = static_cast<decltype(Handle::handle)> (strings.size() + 1);
strings.reserve (strings.size() + text.length() + 1);
if (strings.size() > 100 && (strings.capacity() < (strings.size() + text.length() + 1)))
strings.reserve (strings.size() + 1000);
strings.insert (strings.end(), text.begin(), text.end());
strings.push_back (0);
stringMap.insert (i.first, newHandle);
return { newHandle };
}
@ -3235,9 +3275,41 @@ inline std::string_view SimpleStringDictionary::getStringForHandle (Handle handl
return std::string_view (strings.data() + (handle.handle - 1));
}
inline void SimpleStringDictionary::clear() { strings.clear(); }
inline void SimpleStringDictionary::clear() { strings.clear(); stringMap.clear(); }
inline void SimpleStringDictionary::setRawData (const void* p, size_t n)
{
strings.resize (n);
std::memcpy (strings.data(), p, n);
// Populate string map
for (size_t i = 0; i < strings.size(); ++i)
{
std::string_view sv (strings.data() + i);
auto v = findGreaterThanOrEqual (sv);
stringMap.insert (v.first, static_cast<uint32_t> (i));
i += sv.length();
}
}
inline std::pair<std::vector<uint32_t>::const_iterator, bool> SimpleStringDictionary::findGreaterThanOrEqual (std::string_view v) const
{
bool exactMatch = false;
auto it = std::lower_bound (stringMap.begin(), stringMap.end(), v, [&] (uint32_t i, std::string_view sv) -> bool
{
auto c = sv.compare (getStringForHandle ( { i }));
if (c == 0)
exactMatch = true;
return c > 0;
});
return std::pair (it, exactMatch);
}
} // namespace choc::value
} // anonymous namespace
#endif // CHOC_VALUE_POOL_HEADER_INCLUDED

View file

@ -33,8 +33,6 @@
choc::javascript::createQuickJSContext() to create a context for running
javascript code.
*/
namespace
{
namespace choc::javascript
{
/// This is thrown by any javascript functions that need to report an error
@ -95,23 +93,40 @@ namespace choc::javascript
Context& operator= (Context&&);
~Context();
/// Returns true if the context is valid.
operator bool() const { return pimpl != nullptr; }
//==============================================================================
/// This callback is used by the run() method.
using CompletionHandler = std::function<void(const std::string& error,
const choc::value::ValueView& result)>;
/// Executes some javascript asynchronously.
/// If a CompletionHandler callback is provided, it will be called asynchronously
/// with the return value and any errors that occurred. Note that if you want to execute
/// the script as a module, use runModule() instead.
void run (const std::string& javascriptCode,
CompletionHandler handleResult = {});
/// When parsing modules, this function is expected to take a path to a module, and
/// to return the content of that module, or an empty optional if not found.
using ReadModuleContentFn = std::function<std::optional<std::string>(std::string_view)>;
//==============================================================================
/// Evaluates the given chunk of javascript.
/// If there are any parse errors, this will throw a choc::javascript::Error exception.
/// If the engine supports modules, then providing a value for the resolveModuleContent
/// function will treat the code as a module and will call your function to read the
/// content of any dependencies.
/// None of the methods in this class are either thread-safe or realtime-safe, so you'll
/// need to organise your own locking if you're calling into a single Context from
/// multiple threads.
choc::value::Value evaluate (const std::string& javascriptCode,
ReadModuleContentFn* resolveModuleContent = nullptr);
/// This callback will asynchronously parse the script as a module, and will use the
/// ReadModuleContentFn functor to resolve any imported modules that it needs. If a
/// CompletionHandler callback is provided, it will be called asynchronously with the
/// return value and any errors that occurred.
/// NB: Not all engines support modules.
void runModule (const std::string& moduleCode,
ReadModuleContentFn,
CompletionHandler handleResult = {});
/// Attempts to invoke a global function with no arguments.
/// Evaluates a javascript expression synchronously, and returns the result.
/// If there are any parse errors, this will throw a choc::javascript::Error exception.
/// Note that if you want to execute the script as a module, use runModule() instead.
choc::value::Value evaluateExpression (const std::string& javascriptCode);
/// Attempts to synchronously invoke a global function with no arguments.
/// Any errors will throw a choc::javascript::Error exception.
/// None of the methods in this class are either thread-safe or realtime-safe, so you'll
/// need to organise your own locking if you're calling into a single Context from
@ -153,8 +168,6 @@ namespace choc::javascript
/// @internal
Context (std::unique_ptr<Pimpl>);
Pimpl* getPimpl() const;
private:
std::unique_ptr<Pimpl> pimpl;
};
@ -172,8 +185,13 @@ namespace choc::javascript
/// make sure that your project also has the V8 header folder in its
/// search path, and that you statically link the appropriate V8 libs.
Context createV8Context();
//==============================================================================
/// Sanitises a string to provide a version of it that is safe for use as a
/// javascript identifier. This involves removing/replacing any illegal
/// characters and modifying the string to avoid clashes with reserved words.
std::string makeSafeIdentifier (std::string name);
}
} // anonymous namespace
//==============================================================================
@ -187,8 +205,6 @@ namespace choc::javascript
//
//==============================================================================
namespace
{
namespace choc::javascript
{
@ -207,7 +223,8 @@ struct Context::Pimpl
virtual ~Pimpl() = default;
virtual void registerFunction (const std::string&, NativeFunction) = 0;
virtual choc::value::Value evaluate (const std::string&, ReadModuleContentFn*) = 0;
virtual choc::value::Value evaluateExpression (const std::string&) = 0;
virtual void run (const std::string&, ReadModuleContentFn*, CompletionHandler) = 0;
virtual void prepareForCall (std::string_view, uint32_t numArgs) = 0;
virtual choc::value::Value performCall() = 0;
virtual void pushObjectOrArray (const choc::value::ValueView&) = 0;
@ -277,10 +294,22 @@ inline void Context::registerFunction (const std::string& name, NativeFunction f
pimpl->registerFunction (name, std::move (fn));
}
inline choc::value::Value Context::evaluate (const std::string& javascriptCode, ReadModuleContentFn* resolveModule)
inline choc::value::Value Context::evaluateExpression (const std::string& javascriptCode)
{
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
return pimpl->evaluate (javascriptCode, resolveModule);
return pimpl->evaluateExpression (javascriptCode);
}
inline void Context::run (const std::string& javascriptCode, CompletionHandler handleResult)
{
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
pimpl->run (javascriptCode, nullptr, std::move (handleResult));
}
inline void Context::runModule (const std::string& moduleCode, ReadModuleContentFn readModule, CompletionHandler handleResult)
{
CHOC_ASSERT (pimpl != nullptr); // cannot call this on a moved-from context!
pimpl->run (moduleCode, std::addressof (readModule), std::move (handleResult));
}
inline void Context::pumpMessageLoop()
@ -289,13 +318,40 @@ inline void Context::pumpMessageLoop()
pimpl->pumpMessageLoop();
}
Context::Pimpl* Context::getPimpl() const
inline std::string makeSafeIdentifier (std::string s)
{
return pimpl.get();
constexpr static std::string_view reservedWords[] =
{
"abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch",
"char", "class", "const", "continue", "debugger", "default", "delete", "do",
"double", "else", "enum", "eval", "export", "extends", "false", "final",
"finally", "float", "for", "function", "goto", "if", "implements", "import",
"in", "instanceof", "int", "interface", "let", "long", "native", "new",
"null", "package", "private", "protected", "public", "return", "short", "static",
"super", "switch", "synchronized", "this", "throw", "throws", "transient", "true",
"try", "typeof", "var", "void", "volatile", "while", "with", "yield"
};
for (auto& c : s)
if (std::string_view (" ,./;:").find (c) != std::string_view::npos)
c = '_';
s.erase (std::remove_if (s.begin(), s.end(), [&] (char c)
{
return ! ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9'));
}), s.end());
if (s[0] >= '0' && s[0] <= '9') // Identifiers can't start with a digit
s = "_" + s;
for (auto keyword : reservedWords)
if (s == keyword)
return s + "_";
return s;
}
} // namespace choc::javascript
} // anonymous namespace
#endif // CHOC_JAVASCRIPT_HEADER_INCLUDED

View file

@ -30,14 +30,12 @@
#pragma intrinsic (_BitScanReverse64)
#endif
#ifdef _M_X64
#if defined (_M_X64) && ! defined (_M_ARM64EC)
#pragma intrinsic (_umul128)
#define CHOC_HAS_UMUL128 1
#endif
#endif
namespace
{
namespace choc::math
{
@ -116,6 +114,5 @@ inline Int128 multiply128 (uint64_t a, uint64_t b)
} // namespace choc::math
} // anonymous namespace
#endif

View file

@ -65,14 +65,37 @@
#pragma GCC diagnostic ignored "-Wnarrowing"
#pragma GCC diagnostic ignored "-Wparentheses"
#pragma GCC diagnostic ignored "-Wwrite-strings"
#pragma GCC diagnostic ignored "-Wformat-overflow"
#pragma GCC diagnostic ignored "-Wdeprecated-copy-with-dtor"
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wdeprecated"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic ignored "-Wuse-after-free"
#pragma GCC diagnostic ignored "-Warray-bounds"
#pragma GCC diagnostic ignored "-Wvolatile"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wfloat-equal"
#ifndef __MINGW32__
#pragma GCC diagnostic ignored "-Wredundant-move"
#endif
#else
#pragma warning (push, 0)
#pragma warning (disable: 2440)
#pragma warning (disable: 2664)
#pragma warning (disable: 4244)
#pragma warning (disable: 4701)
#pragma warning (disable: 4702)
#pragma warning (disable: 4706)
#pragma warning (disable: 4722)
#pragma warning (disable: 6011)
#pragma warning (disable: 6246)
#pragma warning (disable: 6255)
#pragma warning (disable: 6262)
#pragma warning (disable: 6297)
#pragma warning (disable: 6308)
#pragma warning (disable: 6323)
#pragma warning (disable: 6340)
#pragma warning (disable: 6385)
#pragma warning (disable: 6386)
#pragma warning (disable: 28182)
#endif

View file

@ -23,8 +23,6 @@
#include <string>
#include "../math/choc_MathHelpers.h"
namespace
{
namespace choc::text
{
@ -395,6 +393,5 @@ inline std::string floatToString (float value, int maxDecimals, bool omitPointIf
inline std::string floatToString (double value, int maxDecimals, bool omitPointIfPossible) { return FloatToStringBuffer<double> (value, maxDecimals, omitPointIfPossible).toString(); }
} // namespace choc::text
} // anonymous namespace
#endif

View file

@ -31,8 +31,6 @@
#undef max // It's never a smart idea to include any C headers before your C++ ones, as it
#undef min // risks polluting your namespace with all kinds of dangerous macros like these ones.
namespace
{
namespace choc::json
{
@ -48,14 +46,14 @@ struct ParseError : public std::runtime_error
/// Parses some JSON text into a choc::value::Value object, using the given pool.
/// Any errors will result in a ParseError exception being thrown.
value::Value parse (text::UTF8Pointer);
[[nodiscard]] value::Value parse (text::UTF8Pointer);
/// Parses some JSON text into a choc::value::Value object, using the given pool.
/// Any errors will result in a ParseError exception being thrown.
value::Value parse (std::string_view);
[[nodiscard]] value::Value parse (std::string_view);
/// Attempts to parse a bare JSON value such as a number, string, object etc
value::Value parseValue (std::string_view);
[[nodiscard]] value::Value parseValue (std::string_view);
/// A helper function to create a JSON-friendly Value object with a set of properties.
/// The argument list must be contain pairs of names and values, e.g.
@ -67,13 +65,13 @@ value::Value parseValue (std::string_view);
/// Essentially, this is a shorthand for calling choc::value::createObject()
/// and passing it an empty type name.
template <typename... Properties>
value::Value create (Properties&&... propertyNamesAndValues);
[[nodiscard]] value::Value create (Properties&&... propertyNamesAndValues);
//==============================================================================
/// Formats a value as a JSON string.
/// If useLineBreaks is true, it'll be formatted as multi-line JSON, if false it'll
/// just be returned as a single line.
std::string toString (const value::ValueView&, bool useLineBreaks = false);
[[nodiscard]] std::string toString (const value::ValueView&, bool useLineBreaks = false);
/// Writes a version of a string to an output stream, with any illegal or non-ascii
/// written as their equivalent JSON escape sequences.
@ -82,15 +80,15 @@ void writeWithEscapeCharacters (OutputStreamType&, text::UTF8Pointer sourceStrin
/// Returns a version of a string with illegal or non-ascii converted into the
/// equivalent JSON escape sequences.
std::string addEscapeCharacters (text::UTF8Pointer sourceString);
[[nodiscard]] std::string addEscapeCharacters (text::UTF8Pointer sourceString);
/// Returns a version of a string with illegal or non-ascii converted into the
/// equivalent JSON escape sequences.
std::string addEscapeCharacters (std::string_view sourceString);
[[nodiscard]] std::string addEscapeCharacters (std::string_view sourceString);
/// Returns a version of a string with illegal or non-ascii converted into the
/// equivalent JSON escape sequences.
std::string getEscapedQuotedString (std::string_view sourceString);
[[nodiscard]] std::string getEscapedQuotedString (std::string_view sourceString);
/// Converts a double to a JSON-format string representation.
std::string doubleToString (double value);
@ -160,7 +158,7 @@ void writeWithEscapeCharacters (OutputStreamType& out, text::UTF8Pointer source)
inline std::string addEscapeCharacters (text::UTF8Pointer source)
{
std::ostringstream result;
std::ostringstream result (std::ios::binary);
writeWithEscapeCharacters (result, source);
return result.str();
}
@ -172,7 +170,7 @@ inline std::string addEscapeCharacters (std::string_view source)
inline std::string getEscapedQuotedString (std::string_view s)
{
std::ostringstream result;
std::ostringstream result (std::ios::binary);
result << '"';
writeWithEscapeCharacters (result, text::UTF8Pointer (std::string (s).c_str()));
result << '"';
@ -287,7 +285,7 @@ void writeAsJSON (Stream& output, const value::ValueView& value, bool useMultipl
inline std::string toString (const value::ValueView& v, bool useLineBreaks)
{
std::ostringstream out;
std::ostringstream out (std::ios::binary);
writeAsJSON (out, v, useLineBreaks);
return out.str();
}
@ -458,7 +456,7 @@ inline value::Value parse (text::UTF8Pointer text, bool parseBareValue)
std::string parseString()
{
std::ostringstream s;
std::ostringstream s (std::ios::binary);
for (;;)
{
@ -559,6 +557,5 @@ value::Value create (Properties&&... properties)
} // namespace choc::json
} // anonymous namespace
#endif

View file

@ -29,8 +29,6 @@
#include <cwctype>
#include "../platform/choc_Assert.h"
namespace
{
namespace choc::text
{
@ -42,77 +40,80 @@ inline bool isDigit (char c) { return static_
/// The arguments must be a sequence of pairs of strings, where the first of each pair is the string to
/// look for, followed by its replacement.
template <typename StringType, typename... OtherReplacements>
std::string replace (StringType textToSearch,
std::string_view firstSubstringToReplace, std::string_view firstReplacement,
OtherReplacements&&... otherPairsOfStringsToReplace);
[[nodiscard]] std::string replace (StringType textToSearch,
std::string_view firstSubstringToReplace, std::string_view firstReplacement,
OtherReplacements&&... otherPairsOfStringsToReplace);
/// Returns a string with any whitespace trimmed from its start and end.
std::string trim (std::string textToTrim);
[[nodiscard]] std::string trim (std::string textToTrim);
/// Returns a string with any whitespace trimmed from its start and end.
std::string_view trim (std::string_view textToTrim);
[[nodiscard]] std::string_view trim (std::string_view textToTrim);
/// Returns a string with any whitespace trimmed from its start and end.
std::string_view trim (const char* textToTrim);
[[nodiscard]] std::string_view trim (const char* textToTrim);
/// Returns a string with any whitespace trimmed from its start.
std::string trimStart (std::string textToTrim);
[[nodiscard]] std::string trimStart (std::string textToTrim);
/// Returns a string with any whitespace trimmed from its start.
std::string_view trimStart (std::string_view textToTrim);
[[nodiscard]] std::string_view trimStart (std::string_view textToTrim);
/// Returns a string with any whitespace trimmed from its start.
std::string_view trimStart (const char* textToTrim);
[[nodiscard]] std::string_view trimStart (const char* textToTrim);
/// Returns a string with any whitespace trimmed from its end.
std::string trimEnd (std::string textToTrim);
[[nodiscard]] std::string trimEnd (std::string textToTrim);
/// Returns a string with any whitespace trimmed from its end.
std::string_view trimEnd (std::string_view textToTrim);
[[nodiscard]] std::string_view trimEnd (std::string_view textToTrim);
/// Returns a string with any whitespace trimmed from its end.
std::string_view trimEnd (const char* textToTrim);
[[nodiscard]] std::string_view trimEnd (const char* textToTrim);
/// If the string begins with one or more instances of the given character, this
/// skips past them, returning the remainder of the string.
std::string_view trimCharacterAtStart (std::string_view textToTrim, char characterToSkip);
[[nodiscard]] std::string_view trimCharacterAtStart (std::string_view textToTrim, char characterToSkip);
/// If the given character is at the start and end of the string, it trims it away.
std::string removeOuterCharacter (std::string text, char outerChar);
[[nodiscard]] std::string removeOuterCharacter (std::string text, char outerChar);
inline std::string removeDoubleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '"'); }
inline std::string removeSingleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '\''); }
[[nodiscard]] inline std::string removeDoubleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '"'); }
[[nodiscard]] inline std::string removeSingleQuotes (std::string text) { return removeOuterCharacter (std::move (text), '\''); }
inline std::string addDoubleQuotes (std::string text) { return "\"" + std::move (text) + "\""; }
inline std::string addSingleQuotes (std::string text) { return "'" + std::move (text) + "'"; }
[[nodiscard]] inline std::string addDoubleQuotes (std::string text) { return "\"" + std::move (text) + "\""; }
[[nodiscard]] inline std::string addSingleQuotes (std::string text) { return "'" + std::move (text) + "'"; }
std::string toLowerCase (std::string);
std::string toUpperCase (std::string);
[[nodiscard]] std::string toLowerCase (std::string);
[[nodiscard]] std::string toUpperCase (std::string);
template <typename IsDelimiterChar>
std::vector<std::string> splitString (std::string_view textToSplit,
IsDelimiterChar&& isDelimiterChar,
bool includeDelimitersInResult);
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
IsDelimiterChar&& isDelimiterChar,
bool includeDelimitersInResult);
template <typename CharStartsDelimiter, typename CharIsInDelimiterBody>
std::vector<std::string> splitString (std::string_view textToSplit,
CharStartsDelimiter&& isDelimiterStart,
CharIsInDelimiterBody&& isDelimiterBody,
bool includeDelimitersInResult);
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
CharStartsDelimiter&& isDelimiterStart,
CharIsInDelimiterBody&& isDelimiterBody,
bool includeDelimitersInResult);
std::vector<std::string> splitString (std::string_view textToSplit,
char delimiterCharacter,
bool includeDelimitersInResult);
[[nodiscard]] std::vector<std::string> splitString (std::string_view textToSplit,
char delimiterCharacter,
bool includeDelimitersInResult);
std::vector<std::string> splitAtWhitespace (std::string_view text, bool keepDelimiters = false);
[[nodiscard]] std::vector<std::string> splitAtWhitespace (std::string_view text,
bool keepDelimiters = false);
/// Splits a string at newline characters, returning an array of strings.
std::vector<std::string> splitIntoLines (std::string_view text, bool includeNewLinesInResult);
[[nodiscard]] std::vector<std::string> splitIntoLines (std::string_view text,
bool includeNewLinesInResult);
/// Joins some kind of array of strings into a single string, adding the given separator
/// between them (but not adding it at the start or end)
template <typename ArrayOfStrings>
std::string joinStrings (const ArrayOfStrings& strings, std::string_view separator);
[[nodiscard]] std::string joinStrings (const ArrayOfStrings& strings,
std::string_view separator);
/// Returns true if this text contains the given sub-string.
bool contains (std::string_view text, std::string_view possibleSubstring);
@ -595,6 +596,5 @@ inline std::string percentEncodeURI (std::string_view text)
} // namespace choc::text
} // anonymous namespace
#endif

View file

@ -22,8 +22,6 @@
#include <cstddef>
#include "choc_StringUtilities.h"
namespace
{
namespace choc::text
{
@ -103,14 +101,14 @@ struct UTF8Pointer
/// Returns a pointer to the first non-whitespace character in the given string (which may
/// be the terminating null character if it's all whitespace).
UTF8Pointer findEndOfWhitespace() const;
[[nodiscard]] UTF8Pointer findEndOfWhitespace() const;
/// Iterates backwards from this position to find the first character that follows
/// a new-line. The pointer provided marks the furthest back that the function should search
UTF8Pointer findStartOfLine (UTF8Pointer startOfValidText) const;
[[nodiscard]] UTF8Pointer findStartOfLine (UTF8Pointer startOfValidText) const;
/// Searches forwards for the next character that is followed by a new-line or a null-terminator.
UTF8Pointer findEndOfLine() const;
[[nodiscard]] UTF8Pointer findEndOfLine() const;
//==============================================================================
struct EndIterator {};
@ -200,7 +198,7 @@ bool isValidCESU8 (std::string_view utf8);
/// Converts any 32-bit characters in this UTF-8 string to surrogate pairs, which makes
/// the resulting string suitable for use at CESU-8.
std::string convertUTF8ToCESU8 (UTF8Pointer);
[[nodiscard]] std::string convertUTF8ToCESU8 (UTF8Pointer);
//==============================================================================
@ -653,6 +651,5 @@ inline std::string convertUTF8ToCESU8 (UTF8Pointer utf8)
} // namespace choc::text
} // anonymous namespace
#endif

View file

@ -32,16 +32,9 @@
==============================================================================
*/
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-copy-with-dtor",
"-Wunused-but-set-variable",
"-Wdeprecated",
"-Wunused-function",
"-Wpedantic")
JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4163 6011 6246 6255 6262 6297 6308 6323 6340 6385 6386 28182)
#define choc juce::detail::choc
#include <juce_core/javascript/choc/javascript/choc_javascript_QuickJS.h>
#include <juce_core/javascript/choc/javascript/choc_javascript.h>
JUCE_END_IGNORE_WARNINGS_MSVC
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#undef choc
namespace juce
{
@ -56,7 +49,7 @@ template <typename T>
static int64_t toJuceInt64 (const T& convertible) { return (int64) (int64_t) convertible; }
//==============================================================================
namespace qjs = choc::javascript::quickjs;
namespace qjs = detail::choc::javascript::quickjs;
using VarOrError = std::variant<var, String>;
@ -412,7 +405,7 @@ static VarOrError quickJSToJuce (const qjs::QuickJSContext::ValuePtr& ptr)
{
return tryQuickJSToJuce (ptr);
}
catch (const choc::javascript::Error& error)
catch (const detail::choc::javascript::Error& error)
{
return String (error.what());
}
@ -428,17 +421,12 @@ class detail::QuickJSWrapper
public:
qjs::JSContext* getQuickJSContext() const
{
return static_cast<qjs::QuickJSContext*> (context.getPimpl())->context;
return impl->context;
}
qjs::JSRuntime* getQuickJSRuntime() const
{
return static_cast<qjs::QuickJSContext*> (context.getPimpl())->runtime;
}
choc::javascript::Context& getContext()
{
return context;
return impl->runtime;
}
/* Returning a value > 0 will interrupt the QuickJS engine.
@ -460,7 +448,7 @@ private:
return 0;
}
choc::javascript::Context context = choc::javascript::createQuickJSContext();
std::unique_ptr<qjs::QuickJSContext> impl = std::make_unique<qjs::QuickJSContext>();
std::function<int()> interruptHandler;
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
@ -558,11 +546,11 @@ struct DynamicObjectWrapper
}
//==============================================================================
static choc::javascript::quickjs::JSValue callDispatcher (qjs::JSContext* ctx,
qjs::JSValueConst thisValue,
int numArgs,
qjs::JSValueConst* args,
int ordinal)
static qjs::JSValue callDispatcher (qjs::JSContext* ctx,
qjs::JSValueConst thisValue,
int numArgs,
qjs::JSValueConst* args,
int ordinal)
{
auto& self = *static_cast<DynamicObjectWrapper*> (qjs::JS_GetOpaque2 (ctx, thisValue, getClassId()));
const auto argList = quickJSToJuce (Span { args, (size_t) numArgs }, ctx);