no message
This commit is contained in:
56
cocos/base/Agent.h
Normal file
56
cocos/base/Agent.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "Macros.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <typename Actor>
|
||||
class CC_DLL Agent : public Actor {
|
||||
public:
|
||||
Agent() noexcept = delete;
|
||||
|
||||
explicit Agent(Actor *const actor) noexcept
|
||||
: Actor(), _actor(actor) {}
|
||||
|
||||
~Agent() override = default;
|
||||
|
||||
Agent(Agent const &) = delete;
|
||||
|
||||
Agent(Agent &&) = delete;
|
||||
|
||||
Agent &operator=(Agent const &) = delete;
|
||||
|
||||
Agent &operator=(Agent &&) = delete;
|
||||
|
||||
inline Actor *getActor() const noexcept { return _actor; }
|
||||
|
||||
protected:
|
||||
Actor *_actor{nullptr};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
181
cocos/base/Assertf.h
Normal file
181
cocos/base/Assertf.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h> // NOLINT
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#if CC_DEBUG && !NDEBUG
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#define CC_ASSERT_FORMAT(cond, fmt, ...) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
char message[256] = {0}; \
|
||||
wchar_t messageTmp[256] = {0}; \
|
||||
snprintf(message, sizeof(message), "CC_ASSERT(%s) failed. " fmt "\n%s", #cond, ##__VA_ARGS__, __FUNCTION__); \
|
||||
std::copy(message, message + strlen(message), messageTmp); \
|
||||
_wassert(messageTmp, _CRT_WIDE(__FILE__), (unsigned)__LINE__); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CC_ABORTF(fmt, ...) \
|
||||
do { \
|
||||
char message[256] = {0}; \
|
||||
wchar_t messageTmp[256] = {0}; \
|
||||
snprintf(message, sizeof(message), fmt, ##__VA_ARGS__); \
|
||||
std::copy(message, message + strlen(message), messageTmp); \
|
||||
_wassert(messageTmp, _CRT_WIDE(__FILE__), (unsigned)__LINE__); \
|
||||
} while (false)
|
||||
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#define CC_ASSERT_FORMAT(cond, fmt, ...) \
|
||||
do { \
|
||||
if (__builtin_expect(!(cond), 0)) { \
|
||||
char message[256] = {0}; \
|
||||
snprintf(message, sizeof(message), "CC_ASSERT(%s) failed. " fmt, #cond, ##__VA_ARGS__); \
|
||||
__assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, message); \
|
||||
} \
|
||||
} while (false)
|
||||
#define CC_ABORTF(fmt, ...) \
|
||||
do { \
|
||||
char message[256] = {0}; \
|
||||
snprintf(message, sizeof(message), fmt, ##__VA_ARGS__); \
|
||||
__assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, message); \
|
||||
} while (false)
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
#define CC_ASSERT_FORMAT(cond, fmt, ...) \
|
||||
do { \
|
||||
if (__builtin_expect(!(cond), 0)) { \
|
||||
char message[256] = {0}; \
|
||||
snprintf(message, sizeof(message), "CC_ASSERT(%s) failed. " fmt, #cond, ##__VA_ARGS__); \
|
||||
__assert(message, __FILE__, __LINE__); \
|
||||
} \
|
||||
} while (false)
|
||||
#define CC_ABORTF(fmt, ...) \
|
||||
do { \
|
||||
char message[256] = {0}; \
|
||||
snprintf(message, sizeof(message), fmt, ##__VA_ARGS__); \
|
||||
__assert(message, __FILE__, __LINE__); \
|
||||
} while (false)
|
||||
#else
|
||||
#define CC_ASSERT_FORMAT(cond, ...) assert(cond)
|
||||
#define CC_ABORTF(fmt, ...) abort()
|
||||
#endif
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
#define _CC_ASSERT_(cond) assert(cond)
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
#define _CC_ASSERTF_CMP(expr1, op, expr2, fmt, ...) \
|
||||
do { \
|
||||
CC_ASSERT_FORMAT((expr1)op(expr2), fmt, ##__VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
// NOLINTNEXTLINE
|
||||
#define _CC_ASSERT_CMP(expr1, op, expr2) \
|
||||
do { \
|
||||
_CC_ASSERT_((expr1)op(expr2)); \
|
||||
} while (false)
|
||||
|
||||
// CC_ASSERTF variants
|
||||
#define CC_ASSERTF_EQ(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, ==, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_NE(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, !=, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_LE(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, <=, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_GE(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, >=, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_LT(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, <, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_GT(expr1, expr2, fmt, ...) _CC_ASSERTF_CMP(expr1, >, expr2, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_TRUE(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, ==, true, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_FALSE(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, ==, false, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_NULL(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, ==, nullptr, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_NOT_NULL(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, !=, nullptr, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_ZERO(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, ==, 0, fmt, ##__VA_ARGS__)
|
||||
#define CC_ASSERTF_NONZERO(expr1, fmt, ...) _CC_ASSERTF_CMP(expr1, !=, 0, fmt, ##__VA_ARGS__)
|
||||
// CC_ASSERT variants
|
||||
#define CC_ASSERT_EQ(expr1, expr2) _CC_ASSERT_CMP(expr1, ==, expr2)
|
||||
#define CC_ASSERT_NE(expr1, expr2) _CC_ASSERT_CMP(expr1, !=, expr2)
|
||||
#define CC_ASSERT_LE(expr1, expr2) _CC_ASSERT_CMP(expr1, <=, expr2)
|
||||
#define CC_ASSERT_GE(expr1, expr2) _CC_ASSERT_CMP(expr1, >=, expr2)
|
||||
#define CC_ASSERT_LT(expr1, expr2) _CC_ASSERT_CMP(expr1, <, expr2)
|
||||
#define CC_ASSERT_GT(expr1, expr2) _CC_ASSERT_CMP(expr1, >, expr2)
|
||||
#define CC_ASSERT_TRUE(expr1) _CC_ASSERT_CMP(expr1, ==, true)
|
||||
#define CC_ASSERT_FALSE(expr1) _CC_ASSERT_CMP(expr1, ==, false)
|
||||
#define CC_ASSERT_NULL(expr1) _CC_ASSERT_CMP(expr1, ==, nullptr)
|
||||
#define CC_ASSERT_NOT_NULL(expr1) _CC_ASSERT_CMP(expr1, !=, nullptr)
|
||||
#define CC_ASSERT_ZERO(expr1) _CC_ASSERT_CMP(expr1, ==, 0)
|
||||
#define CC_ASSERT_NONZERO(expr1) _CC_ASSERT_CMP(expr1, !=, 0)
|
||||
/**
|
||||
* @brief printf like assert
|
||||
*
|
||||
* CC_ASSERTF(1==2, "value %d should not be equal to %d", 1, 2);
|
||||
* CC_ASSERTF_EQ(1, 3/3, "n equals to n");
|
||||
* CC_ASSERTF_NE(1, s, "not initial value");
|
||||
*
|
||||
*/
|
||||
#define CC_ASSERTF(cond, fmt, ...) CC_ASSERT_FORMAT(cond, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* CC_ABORT call abort() in debug mode.
|
||||
*
|
||||
* printf like abort: CC_ABORTF
|
||||
*
|
||||
* CC_ABORTF("Dead Code")
|
||||
* CC_ABORTF("Invalidate state code %d", statusCode);
|
||||
* CC_ABORTF("Should crash in debug mode")
|
||||
*/
|
||||
#define CC_ABORT() abort()
|
||||
#define CC_ASSERT(cond) _CC_ASSERT_(cond)
|
||||
|
||||
#else
|
||||
#define CC_ASSERTF(...) ((void)0)
|
||||
#define CC_ASSERTF_EQ(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_NE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_LE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_GE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_LT(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_GT(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERTF_TRUE(expr1, ...) ((void)0)
|
||||
#define CC_ASSERTF_FALSE(expr1, ...) ((void)0)
|
||||
#define CC_ASSERTF_NULL(expr1, ...) ((void)0)
|
||||
#define CC_ASSERTF_NOT_NULL(expr1, ...) ((void)0)
|
||||
#define CC_ASSERTF_ZERO(expr1, ...) ((void)0)
|
||||
#define CC_ASSERTF_NONZERO(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT(...) ((void)0)
|
||||
#define CC_ASSERT_EQ(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_NE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_LE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_GE(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_LT(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_GT(expr1, expr2, ...) ((void)0)
|
||||
#define CC_ASSERT_TRUE(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT_FALSE(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT_NULL(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT_NOT_NULL(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT_ZERO(expr1, ...) ((void)0)
|
||||
#define CC_ASSERT_NONZERO(expr1, ...) ((void)0)
|
||||
#define CC_ABORTF(...) ((void)0) // ignored in release builds
|
||||
#define CC_ABORT() ((void)0) // ignored in release builds
|
||||
#endif
|
||||
46
cocos/base/BinaryArchive.cpp
Normal file
46
cocos/base/BinaryArchive.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "BinaryArchive.h"
|
||||
#include "base/Assertf.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
bool BinaryInputArchive::load(char *data, uint32_t size) {
|
||||
CC_ASSERT(!!_stream);
|
||||
return _stream.rdbuf()->sgetn(data, size) == size;
|
||||
}
|
||||
|
||||
void BinaryInputArchive::move(uint32_t length) {
|
||||
CC_ASSERT(!!_stream);
|
||||
_stream.ignore(length);
|
||||
}
|
||||
|
||||
void BinaryOutputArchive::save(const char *data, uint32_t size) {
|
||||
CC_ASSERT(!!_stream);
|
||||
auto len = _stream.rdbuf()->sputn(data, size);
|
||||
CC_ASSERT(len == size);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
93
cocos/base/BinaryArchive.h
Normal file
93
cocos/base/BinaryArchive.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* Binary input stream archive.
|
||||
*/
|
||||
class BinaryInputArchive {
|
||||
public:
|
||||
explicit BinaryInputArchive(std::istream &stream) : _stream(stream) {}
|
||||
~BinaryInputArchive() = default;
|
||||
|
||||
/**
|
||||
* Read data from stream.
|
||||
* @param data Pointer to data address to read.
|
||||
* @param size Length of the data.
|
||||
*/
|
||||
bool load(char *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* Read arithmetic data from stream.
|
||||
* @param val Data to read.
|
||||
*/
|
||||
template <typename T, typename = std::enable_if<std::is_arithmetic_v<T>>>
|
||||
bool load(T &val) {
|
||||
return load(reinterpret_cast<char *>(std::addressof(val)), sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip data length
|
||||
* @param length Skip length
|
||||
*/
|
||||
void move(uint32_t length);
|
||||
|
||||
private:
|
||||
std::istream &_stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* Binary output stream archive.
|
||||
*/
|
||||
class BinaryOutputArchive {
|
||||
public:
|
||||
explicit BinaryOutputArchive(std::ostream &stream) : _stream(stream) {}
|
||||
~BinaryOutputArchive() = default;
|
||||
|
||||
/**
|
||||
* Write data to stream.
|
||||
* @param data Pointer to data address to write.
|
||||
* @param size Length of the data.
|
||||
*/
|
||||
void save(const char *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* Write arithmetic data to stream.
|
||||
* @param val Data to write.
|
||||
*/
|
||||
template <typename T, typename = std::enable_if<std::is_arithmetic_v<T>>>
|
||||
void save(const T &v) {
|
||||
save(reinterpret_cast<const char *>(std::addressof(v)), sizeof(T));
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream &_stream;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
77
cocos/base/Compressed.cpp
Normal file
77
cocos/base/Compressed.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "base/Compressed.h"
|
||||
#include "base/Utils.h"
|
||||
|
||||
// compressed file header
|
||||
static const uint32_t COMPRESSED_HEADER_LENGTH = 4;
|
||||
static const uint32_t COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH = 4;
|
||||
static const uint32_t COMPRESSED_MIPMAP_DATA_SIZE_LENGTH = 4;
|
||||
static const uint32_t COMPRESSED_MAGIC = 0x50494d43;
|
||||
|
||||
bool compressedIsValid(const unsigned char* pFile) {
|
||||
const uint32_t magic = static_cast<uint32_t>(pFile[0]) +
|
||||
static_cast<uint32_t>(pFile[1]) * 256 +
|
||||
static_cast<uint32_t>(pFile[2]) * 65536 +
|
||||
static_cast<uint32_t>(pFile[3]) * 16777216;
|
||||
|
||||
return magic == COMPRESSED_MAGIC;
|
||||
}
|
||||
|
||||
uint32_t getChunkNumbers(const unsigned char* pFile) {
|
||||
return static_cast<uint32_t>(pFile[COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + 0]) +
|
||||
static_cast<uint32_t>(pFile[COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + 1]) * 256 +
|
||||
static_cast<uint32_t>(pFile[COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + 2]) * 65536 +
|
||||
static_cast<uint32_t>(pFile[COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + 3]) * 16777216;
|
||||
}
|
||||
|
||||
uint32_t getChunkSizes(const unsigned char* pFile, uint32_t level) {
|
||||
const uint32_t byteOffset = COMPRESSED_HEADER_LENGTH + COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + COMPRESSED_MIPMAP_DATA_SIZE_LENGTH * level;
|
||||
return (pFile[byteOffset + 0]) +
|
||||
(pFile[byteOffset + 1]) * 256 +
|
||||
(pFile[byteOffset + 2]) * 65536 +
|
||||
(pFile[byteOffset + 3]) * 16777216;
|
||||
}
|
||||
|
||||
unsigned char* getChunk(const unsigned char* pFile, uint32_t level) {
|
||||
unsigned char* dstData = nullptr;
|
||||
const auto chunkCount = getChunkNumbers(pFile);
|
||||
const auto compressedFileHeaderLength = COMPRESSED_HEADER_LENGTH + COMPRESSED_MIPMAP_LEVEL_COUNT_LENGTH + COMPRESSED_MIPMAP_DATA_SIZE_LENGTH * chunkCount;
|
||||
|
||||
uint32_t byteOffset = compressedFileHeaderLength;
|
||||
for (uint32_t i = 0; i < chunkCount; ++i) {
|
||||
const auto chunkSize = getChunkSizes(pFile, i);
|
||||
if (i == level) {
|
||||
dstData = static_cast<unsigned char*>(malloc(chunkSize * sizeof(unsigned char)));
|
||||
memcpy(dstData, pFile + byteOffset, chunkSize);
|
||||
break;
|
||||
}
|
||||
byteOffset += chunkSize;
|
||||
}
|
||||
|
||||
return dstData;
|
||||
}
|
||||
38
cocos/base/Compressed.h
Normal file
38
cocos/base/Compressed.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Check if a compressed file header is correctly formatted
|
||||
bool compressedIsValid(const unsigned char *pFile);
|
||||
|
||||
// Read the chunks count from compressed header
|
||||
uint32_t getChunkNumbers(const unsigned char *pFile);
|
||||
|
||||
// Read the chunk size from compressed header
|
||||
uint32_t getChunkSizes(const unsigned char *pFile, uint32_t level);
|
||||
|
||||
// Read the chunk from compressed header
|
||||
unsigned char *getChunk(const unsigned char *pFile, uint32_t level);
|
||||
69
cocos/base/Config.h
Normal file
69
cocos/base/Config.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
/** Support PNG or not. If your application don't use png format picture, you can undefine this macro to save package size.
|
||||
*/
|
||||
#ifndef CC_USE_PNG
|
||||
#define CC_USE_PNG 1
|
||||
#endif // CC_USE_PNG
|
||||
|
||||
/** Support JPEG or not. If your application don't use jpeg format picture, you can undefine this macro to save package size.
|
||||
*/
|
||||
#ifndef CC_USE_JPEG
|
||||
#define CC_USE_JPEG 1
|
||||
#endif // CC_USE_JPEG
|
||||
|
||||
/** Support webp or not. If your application don't use webp format picture, you can undefine this macro to save package size.
|
||||
*/
|
||||
#ifndef CC_USE_WEBP
|
||||
#define CC_USE_WEBP 1
|
||||
#endif // CC_USE_WEBP
|
||||
|
||||
/** Support EditBox
|
||||
*/
|
||||
#ifndef CC_USE_EDITBOX
|
||||
#define CC_USE_EDITBOX 1
|
||||
#endif
|
||||
|
||||
#ifndef CC_FILEUTILS_APPLE_ENABLE_OBJC
|
||||
#define CC_FILEUTILS_APPLE_ENABLE_OBJC 1
|
||||
#endif
|
||||
|
||||
#ifndef CC_ENABLE_CACHE_JSB_FUNC_RESULT
|
||||
#define CC_ENABLE_CACHE_JSB_FUNC_RESULT 1
|
||||
#endif
|
||||
|
||||
#ifndef USE_MEMORY_LEAK_DETECTOR
|
||||
#define USE_MEMORY_LEAK_DETECTOR 0
|
||||
#endif
|
||||
|
||||
#ifndef CC_USE_PROFILER
|
||||
#define CC_USE_PROFILER 0
|
||||
#endif
|
||||
130
cocos/base/Data.cpp
Normal file
130
cocos/base/Data.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Data.h"
|
||||
#include <cstring>
|
||||
#include "base/Log.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
const Data Data::NULL_DATA;
|
||||
|
||||
Data::Data() = default;
|
||||
|
||||
Data::Data(Data &&other) noexcept {
|
||||
// CC_LOG_INFO("In the move constructor of Data.");
|
||||
move(other);
|
||||
}
|
||||
|
||||
Data::Data(const Data &other) {
|
||||
// CC_LOG_INFO("In the copy constructor of Data.");
|
||||
copy(other._bytes, other._size);
|
||||
}
|
||||
|
||||
Data::~Data() {
|
||||
// CC_LOG_INFO("deallocing Data: %p", this);
|
||||
clear();
|
||||
}
|
||||
|
||||
Data &Data::operator=(const Data &other) {
|
||||
// CC_LOG_INFO("In the copy assignment of Data.");
|
||||
if (this != &other) {
|
||||
copy(other._bytes, other._size);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Data &Data::operator=(Data &&other) noexcept {
|
||||
// CC_LOG_INFO("In the move assignment of Data.");
|
||||
move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Data::move(Data &other) {
|
||||
clear();
|
||||
|
||||
_bytes = other._bytes;
|
||||
_size = other._size;
|
||||
|
||||
other._bytes = nullptr;
|
||||
other._size = 0;
|
||||
}
|
||||
|
||||
bool Data::isNull() const {
|
||||
return (_bytes == nullptr || _size == 0);
|
||||
}
|
||||
|
||||
uint8_t *Data::getBytes() const {
|
||||
return _bytes;
|
||||
}
|
||||
|
||||
uint32_t Data::getSize() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
void Data::copy(const unsigned char *bytes, uint32_t size) {
|
||||
clear();
|
||||
|
||||
if (size > 0) {
|
||||
_size = size;
|
||||
_bytes = static_cast<unsigned char *>(malloc(sizeof(unsigned char) * _size));
|
||||
memcpy(_bytes, bytes, _size);
|
||||
}
|
||||
}
|
||||
|
||||
void Data::fastSet(unsigned char *bytes, uint32_t size) {
|
||||
free(_bytes);
|
||||
_bytes = bytes;
|
||||
_size = size;
|
||||
}
|
||||
|
||||
void Data::resize(uint32_t size) {
|
||||
CC_ASSERT(size);
|
||||
if (_size == size) {
|
||||
return;
|
||||
}
|
||||
_size = size;
|
||||
_bytes = static_cast<unsigned char *>(realloc(_bytes, sizeof(unsigned char) * _size));
|
||||
}
|
||||
|
||||
void Data::clear() {
|
||||
free(_bytes);
|
||||
_bytes = nullptr;
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
uint8_t *Data::takeBuffer(uint32_t *size) {
|
||||
auto *buffer = getBytes();
|
||||
if (size) {
|
||||
*size = getSize();
|
||||
}
|
||||
|
||||
_bytes = nullptr;
|
||||
_size = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
145
cocos/base/Data.h
Normal file
145
cocos/base/Data.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class CC_DLL Data {
|
||||
friend class Properties;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This parameter is defined for convenient reference if a null Data object is needed.
|
||||
*/
|
||||
static const Data NULL_DATA;
|
||||
|
||||
/**
|
||||
* Constructor of Data.
|
||||
*/
|
||||
Data();
|
||||
|
||||
/**
|
||||
* Copy constructor of Data.
|
||||
*/
|
||||
Data(const Data &other);
|
||||
|
||||
/**
|
||||
* Copy constructor of Data.
|
||||
*/
|
||||
Data(Data &&other) noexcept;
|
||||
|
||||
/**
|
||||
* Destructor of Data.
|
||||
*/
|
||||
~Data();
|
||||
|
||||
/**
|
||||
* Overloads of operator=.
|
||||
*/
|
||||
Data &operator=(const Data &other);
|
||||
|
||||
/**
|
||||
* Overloads of operator=.
|
||||
*/
|
||||
Data &operator=(Data &&other) noexcept;
|
||||
|
||||
/**
|
||||
* Gets internal bytes of Data. It will return the pointer directly used in Data, so don't delete it.
|
||||
*
|
||||
* @return Pointer of bytes used internal in Data.
|
||||
*/
|
||||
uint8_t *getBytes() const;
|
||||
|
||||
/**
|
||||
* Gets the size of the bytes.
|
||||
*
|
||||
* @return The size of bytes of Data.
|
||||
*/
|
||||
uint32_t getSize() const;
|
||||
|
||||
/** Copies the buffer pointer and its size.
|
||||
* @note This method will copy the whole buffer.
|
||||
* Developer should free the pointer after invoking this method.
|
||||
* @see Data::fastSet
|
||||
*/
|
||||
void copy(const unsigned char *bytes, uint32_t size);
|
||||
|
||||
/** Fast set the buffer pointer and its size. Please use it carefully.
|
||||
* @param bytes The buffer pointer, note that it have to be allocated by 'malloc' or 'calloc',
|
||||
* since in the destructor of Data, the buffer will be deleted by 'free'.
|
||||
* @note 1. This method will move the ownship of 'bytes'pointer to Data,
|
||||
* 2. The pointer should not be used outside after it was passed to this method.
|
||||
* @see Data::copy
|
||||
*/
|
||||
void fastSet(unsigned char *bytes, uint32_t size);
|
||||
|
||||
void resize(uint32_t size);
|
||||
|
||||
/**
|
||||
* Clears data, free buffer and reset data size.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Check whether the data is null.
|
||||
*
|
||||
* @return True if the Data is null, false if not.
|
||||
*/
|
||||
bool isNull() const;
|
||||
|
||||
/**
|
||||
* Get the internal buffer of data and set data to empty state.
|
||||
*
|
||||
* The ownership of the buffer removed from the data object.
|
||||
* That is the user have to free the returned buffer.
|
||||
* The data object is set to empty state, that is internal buffer is set to nullptr
|
||||
* and size is set to zero.
|
||||
* Usage:
|
||||
* @code
|
||||
* Data d;
|
||||
* // ...
|
||||
* uint32_t size;
|
||||
* uint8_t* buffer = d.takeBuffer(&size);
|
||||
* // use buffer and size
|
||||
* free(buffer);
|
||||
* @endcode
|
||||
*
|
||||
* @param size Will fill with the data buffer size in bytes, if you do not care buffer size, pass nullptr.
|
||||
* @return the internal data buffer, free it after use.
|
||||
*/
|
||||
unsigned char *takeBuffer(uint32_t *size = nullptr);
|
||||
|
||||
private:
|
||||
void move(Data &other); //NOLINT
|
||||
|
||||
uint8_t *_bytes{nullptr};
|
||||
uint32_t _size{0};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
62
cocos/base/DeferredReleasePool.cpp
Normal file
62
cocos/base/DeferredReleasePool.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/DeferredReleasePool.h"
|
||||
#include "base/Log.h"
|
||||
namespace cc {
|
||||
|
||||
ccstd::vector<RefCounted *> DeferredReleasePool::managedObjectArray{};
|
||||
|
||||
void DeferredReleasePool::add(RefCounted *object) {
|
||||
DeferredReleasePool::managedObjectArray.push_back(object);
|
||||
}
|
||||
|
||||
void DeferredReleasePool::clear() {
|
||||
for (const auto &obj : DeferredReleasePool::managedObjectArray) {
|
||||
obj->release();
|
||||
}
|
||||
DeferredReleasePool::managedObjectArray.clear();
|
||||
}
|
||||
|
||||
bool DeferredReleasePool::contains(RefCounted *object) {
|
||||
for (const auto &obj : DeferredReleasePool::managedObjectArray) { // NOLINT(readability-use-anyofallof) // remove after using C++20
|
||||
if (obj == object) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeferredReleasePool::dump() {
|
||||
CC_LOG_DEBUG("number of managed object %ul\n", DeferredReleasePool::managedObjectArray.size());
|
||||
CC_LOG_DEBUG("%20s%20s%20s", "Object pointer", "Object id", "reference count");
|
||||
for (const auto &obj : DeferredReleasePool::managedObjectArray) {
|
||||
CC_UNUSED_PARAM(obj);
|
||||
CC_LOG_DEBUG("%20p%20u\n", obj, obj->getRefCount());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
69
cocos/base/DeferredReleasePool.h
Normal file
69
cocos/base/DeferredReleasePool.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class CC_DLL DeferredReleasePool {
|
||||
public:
|
||||
static void add(RefCounted *object);
|
||||
static void clear();
|
||||
|
||||
/**
|
||||
* Checks whether the autorelease pool contains the specified object.
|
||||
*
|
||||
* @param object The object to be checked.
|
||||
* @return True if the autorelease pool contains the object, false if not
|
||||
*/
|
||||
static bool contains(RefCounted *object);
|
||||
|
||||
/**
|
||||
* Dump the objects that are put into the autorelease pool. It is used for debugging.
|
||||
*
|
||||
* The result will look like:
|
||||
* Object pointer address object id reference count
|
||||
*/
|
||||
static void dump();
|
||||
|
||||
private:
|
||||
/**
|
||||
* The underlying array of object managed by the pool.
|
||||
*
|
||||
* Although Array retains the object once when an object is added, proper
|
||||
* Ref::release() is called outside the array to make sure that the pool
|
||||
* does not affect the managed object's reference count. So an object can
|
||||
* be destructed properly by calling Ref::release() even if the object
|
||||
* is in the pool.
|
||||
*/
|
||||
static ccstd::vector<RefCounted *> managedObjectArray;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
97
cocos/base/HasMemberFunction.h
Normal file
97
cocos/base/HasMemberFunction.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
/* This macro is used for checking whether a member function exists in a class in compiling time.
|
||||
Usage:
|
||||
If we have a class called `MyClass` as follows:
|
||||
|
||||
```c++
|
||||
class MyClass {
|
||||
public:
|
||||
int myMethod(bool a, float b) { return 100; }
|
||||
};
|
||||
```
|
||||
|
||||
Test code:
|
||||
```c++
|
||||
#include "base/HasMemberFunction.h"
|
||||
|
||||
CC_DEFINE_HAS_MEMBER_FUNC(myMethod)
|
||||
|
||||
template <typename T>
|
||||
void myTest(T* arg0) {
|
||||
if constexpr (has_myMethod<T, int(bool, float)>::value) {
|
||||
// <1>: DO SOMETHING if T owns `myMethod` function.
|
||||
// ...
|
||||
} else {
|
||||
// <2>: DO SOMETHING if T doesn't own `myMethod` function.
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
static int myTestEntry() {
|
||||
MyClass a;
|
||||
myTest(&a); // --> Go to <1>
|
||||
int b;
|
||||
myTest(&b; // --> Go to <2>
|
||||
}
|
||||
|
||||
```
|
||||
*/
|
||||
|
||||
#define CC_DEFINE_HAS_MEMBER_FUNC(memFunc) \
|
||||
template <typename, typename T> \
|
||||
struct has_##memFunc { \
|
||||
static_assert( \
|
||||
std::integral_constant<T, false>::value, \
|
||||
"Second template parameter needs to be of function type."); \
|
||||
}; \
|
||||
\
|
||||
template <typename C, typename Ret, typename... Args> \
|
||||
struct has_##memFunc<C, Ret(Args...)> { \
|
||||
private: \
|
||||
template <typename T> \
|
||||
static constexpr auto check(T*) \
|
||||
-> typename std::is_same< \
|
||||
decltype(std::declval<T>().memFunc(std::declval<Args>()...)), \
|
||||
Ret>::type; \
|
||||
\
|
||||
template <typename> \
|
||||
static constexpr std::false_type check(...); \
|
||||
typedef decltype(check<C>(0)) type; \
|
||||
\
|
||||
public: \
|
||||
static constexpr bool value = type::value; \
|
||||
};
|
||||
|
||||
namespace cc {
|
||||
|
||||
CC_DEFINE_HAS_MEMBER_FUNC(setScriptObject)
|
||||
CC_DEFINE_HAS_MEMBER_FUNC(getScriptObject)
|
||||
|
||||
} // namespace cc
|
||||
89
cocos/base/IndexHandle.h
Normal file
89
cocos/base/IndexHandle.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <typename Index, typename Enable = std::enable_if_t<std::is_integral<Index>::value>>
|
||||
class IndexHandle {
|
||||
public:
|
||||
struct Hasher {
|
||||
inline std::size_t operator()(IndexHandle const &s) const noexcept { return s._index; }
|
||||
};
|
||||
|
||||
using IndexType = Index;
|
||||
|
||||
IndexHandle() noexcept = default;
|
||||
explicit IndexHandle(IndexType index) noexcept : _index(index) {}
|
||||
|
||||
inline bool isValid() const noexcept;
|
||||
inline void clear() noexcept;
|
||||
|
||||
inline bool operator<(IndexHandle const &rhs) const noexcept;
|
||||
inline bool operator==(IndexHandle const &rhs) const noexcept;
|
||||
inline bool operator!=(IndexHandle const &rhs) const noexcept;
|
||||
inline operator IndexType() const noexcept; // NOLINT(google-explicit-constructor) we need this implicitly
|
||||
|
||||
static IndexType constexpr UNINITIALIZED{std::numeric_limits<IndexType>::max()};
|
||||
|
||||
private:
|
||||
IndexType _index{UNINITIALIZED};
|
||||
};
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
bool IndexHandle<Index, Enable>::isValid() const noexcept {
|
||||
return _index != UNINITIALIZED;
|
||||
}
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
void IndexHandle<Index, Enable>::clear() noexcept {
|
||||
_index = UNINITIALIZED;
|
||||
}
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
bool IndexHandle<Index, Enable>::operator<(IndexHandle const &rhs) const noexcept {
|
||||
return _index < rhs._index;
|
||||
}
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
bool IndexHandle<Index, Enable>::operator==(IndexHandle const &rhs) const noexcept {
|
||||
return (_index == rhs._index);
|
||||
}
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
bool IndexHandle<Index, Enable>::operator!=(IndexHandle const &rhs) const noexcept {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
template <typename Index, typename Enable>
|
||||
IndexHandle<Index, Enable>::operator IndexType() const noexcept {
|
||||
return _index;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
91
cocos/base/Locked.h
Normal file
91
cocos/base/Locked.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <class T, class LK>
|
||||
class UniqueLockedRef {
|
||||
public:
|
||||
UniqueLockedRef(T *t, LK *mtx) : _data(t), _mtx(mtx) {
|
||||
_mtx->lock();
|
||||
}
|
||||
UniqueLockedRef(UniqueLockedRef &&t) noexcept {
|
||||
_data = t._data;
|
||||
_mtx = t._mtx;
|
||||
t._data = nullptr;
|
||||
t._mtx = nullptr;
|
||||
}
|
||||
|
||||
UniqueLockedRef &operator=(UniqueLockedRef &&t) noexcept {
|
||||
_data = t._data;
|
||||
_mtx = t._mtx;
|
||||
t._data = nullptr;
|
||||
t._mtx = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
UniqueLockedRef(const T &t) = delete;
|
||||
UniqueLockedRef &operator=(const UniqueLockedRef &) = delete;
|
||||
|
||||
~UniqueLockedRef() {
|
||||
if (_mtx) {
|
||||
_mtx->unlock();
|
||||
}
|
||||
}
|
||||
|
||||
T *operator->() {
|
||||
return _data;
|
||||
}
|
||||
T &operator*() {
|
||||
return *_data;
|
||||
}
|
||||
|
||||
private:
|
||||
T *_data{};
|
||||
LK *_mtx{};
|
||||
};
|
||||
|
||||
template <class T, class LK>
|
||||
class Locked {
|
||||
public:
|
||||
Locked() = default;
|
||||
Locked(const Locked &) = delete;
|
||||
Locked(Locked &&) = delete;
|
||||
Locked &operator=(const Locked &) = delete;
|
||||
Locked &operator=(Locked &&) = delete;
|
||||
UniqueLockedRef<T, LK> lock() {
|
||||
UniqueLockedRef<T, LK> ref(&_data, &_mutex);
|
||||
return std::move(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
LK _mutex{};
|
||||
T _data{};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
239
cocos/base/Log.cpp
Normal file
239
cocos/base/Log.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
|
||||
#define COLOR_FATAL FOREGROUND_INTENSITY | FOREGROUND_RED
|
||||
#define COLOR_ERROR FOREGROUND_RED
|
||||
#define COLOR_WARN 6
|
||||
#define COLOR_INFO FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
#define COLOR_DEBUG 7
|
||||
#define COLOR_NORMAL 8
|
||||
#define SET_CONSOLE_TEXT_COLOR(color) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color)
|
||||
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#include <android/log.h>
|
||||
#elif CC_PLATFORM == CC_PLATFORM_OHOS
|
||||
#include <hilog/log.h>
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_OPENHARMONY)
|
||||
#include <hilog/log.h>
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
#define LOG_USE_TIMESTAMP
|
||||
#if (CC_DEBUG == 1)
|
||||
LogLevel Log::slogLevel = LogLevel::LEVEL_DEBUG;
|
||||
#else
|
||||
LogLevel Log::slogLevel = LogLevel::INFO;
|
||||
#endif
|
||||
|
||||
FILE *Log::slogFile = nullptr;
|
||||
const ccstd::vector<ccstd::string> LOG_LEVEL_DESCS{"FATAL", "ERROR", "WARN", "INFO", "DEBUG"};
|
||||
|
||||
void Log::setLogFile(const ccstd::string &filename) {
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
if (slogFile) {
|
||||
fclose(slogFile);
|
||||
}
|
||||
|
||||
slogFile = fopen(filename.c_str(), "w");
|
||||
|
||||
if (slogFile) {
|
||||
ccstd::string msg;
|
||||
msg += "------------------------------------------------------\n";
|
||||
|
||||
struct tm *tm_time;
|
||||
time_t ct_time;
|
||||
time(&ct_time);
|
||||
tm_time = localtime(&ct_time);
|
||||
char dateBuffer[256] = {0};
|
||||
snprintf(dateBuffer, sizeof(dateBuffer), "LOG DATE: %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||
tm_time->tm_year + 1900,
|
||||
tm_time->tm_mon + 1,
|
||||
tm_time->tm_mday,
|
||||
tm_time->tm_hour,
|
||||
tm_time->tm_min,
|
||||
tm_time->tm_sec);
|
||||
|
||||
msg += dateBuffer;
|
||||
|
||||
msg += "------------------------------------------------------\n";
|
||||
|
||||
fputs(msg.c_str(), slogFile);
|
||||
fflush(slogFile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Log::close() {
|
||||
if (slogFile) {
|
||||
fclose(slogFile);
|
||||
slogFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Log::logMessage(LogType type, LogLevel level, const char *formats, ...) {
|
||||
char buff[4096];
|
||||
char *p = buff;
|
||||
char *last = buff + sizeof(buff) - 3;
|
||||
|
||||
#if defined(LOG_USE_TIMESTAMP)
|
||||
struct tm *tmTime;
|
||||
time_t ctTime;
|
||||
time(&ctTime);
|
||||
tmTime = localtime(&ctTime);
|
||||
|
||||
p += sprintf(p, "%02d:%02d:%02d ", tmTime->tm_hour, tmTime->tm_min, tmTime->tm_sec);
|
||||
#endif
|
||||
|
||||
p += sprintf(p, "[%s]: ", LOG_LEVEL_DESCS[static_cast<int>(level)].c_str());
|
||||
|
||||
va_list args;
|
||||
va_start(args, formats);
|
||||
// p += StringUtil::vprintf(p, last, formats, args);
|
||||
|
||||
std::ptrdiff_t count = (last - p);
|
||||
int ret = vsnprintf(p, count, formats, args);
|
||||
if (ret >= count - 1) {
|
||||
p += (count - 1);
|
||||
} else if (ret >= 0) {
|
||||
p += ret;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
*p++ = '\n';
|
||||
*p = 0;
|
||||
|
||||
if (slogFile) {
|
||||
fputs(buff, slogFile);
|
||||
fflush(slogFile);
|
||||
}
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
WCHAR wszBuf[4096] = {0};
|
||||
MultiByteToWideChar(CP_UTF8, 0, buff, -1, wszBuf, sizeof(wszBuf));
|
||||
|
||||
WORD color;
|
||||
switch (level) {
|
||||
case LogLevel::LEVEL_DEBUG: color = COLOR_DEBUG; break;
|
||||
case LogLevel::INFO: color = COLOR_INFO; break;
|
||||
case LogLevel::WARN: color = COLOR_WARN; break;
|
||||
case LogLevel::ERR: color = COLOR_ERROR; break;
|
||||
case LogLevel::FATAL: color = COLOR_FATAL; break;
|
||||
default: color = COLOR_INFO;
|
||||
}
|
||||
SET_CONSOLE_TEXT_COLOR(color);
|
||||
wprintf(L"%s", wszBuf);
|
||||
SET_CONSOLE_TEXT_COLOR(COLOR_NORMAL);
|
||||
|
||||
OutputDebugStringW(wszBuf);
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
android_LogPriority priority;
|
||||
switch (level) {
|
||||
case LogLevel::LEVEL_DEBUG:
|
||||
priority = ANDROID_LOG_DEBUG;
|
||||
break;
|
||||
case LogLevel::INFO:
|
||||
priority = ANDROID_LOG_INFO;
|
||||
break;
|
||||
case LogLevel::WARN:
|
||||
priority = ANDROID_LOG_WARN;
|
||||
break;
|
||||
case LogLevel::ERR:
|
||||
priority = ANDROID_LOG_ERROR;
|
||||
break;
|
||||
case LogLevel::FATAL:
|
||||
priority = ANDROID_LOG_FATAL;
|
||||
break;
|
||||
default:
|
||||
priority = ANDROID_LOG_INFO;
|
||||
}
|
||||
|
||||
__android_log_write(priority, (type == LogType::KERNEL ? "Cocos" : "CocosScript"), buff);
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_OHOS)
|
||||
const char *typeStr = (type == LogType::KERNEL ? "Cocos %{public}s" : "CocosScript %{public}s");
|
||||
switch (level) {
|
||||
case LogLevel::LEVEL_DEBUG:
|
||||
HILOG_DEBUG(LOG_APP, typeStr, (const char *)buff);
|
||||
break;
|
||||
case LogLevel::INFO:
|
||||
HILOG_INFO(LOG_APP, typeStr, buff);
|
||||
break;
|
||||
case LogLevel::WARN:
|
||||
HILOG_WARN(LOG_APP, typeStr, buff);
|
||||
break;
|
||||
case LogLevel::ERR:
|
||||
HILOG_ERROR(LOG_APP, typeStr, buff);
|
||||
break;
|
||||
case LogLevel::FATAL:
|
||||
HILOG_FATAL(LOG_APP, typeStr, buff);
|
||||
break;
|
||||
default:
|
||||
HILOG_DEBUG(LOG_APP, typeStr, buff);
|
||||
}
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_OPENHARMONY)
|
||||
::LogLevel ohosLoglevel = ::LogLevel::LOG_DEBUG;
|
||||
switch (level) {
|
||||
case LogLevel::LEVEL_DEBUG:
|
||||
ohosLoglevel = ::LogLevel::LOG_DEBUG;
|
||||
break;
|
||||
case LogLevel::INFO:
|
||||
ohosLoglevel = ::LogLevel::LOG_INFO;
|
||||
break;
|
||||
case LogLevel::WARN:
|
||||
ohosLoglevel = ::LogLevel::LOG_WARN;
|
||||
break;
|
||||
case LogLevel::ERR:
|
||||
ohosLoglevel = ::LogLevel::LOG_ERROR;
|
||||
break;
|
||||
case LogLevel::FATAL:
|
||||
ohosLoglevel = ::LogLevel::LOG_FATAL;
|
||||
break;
|
||||
default:
|
||||
ohosLoglevel = ::LogLevel::LOG_INFO;
|
||||
break;
|
||||
}
|
||||
OH_LOG_Print(LOG_APP, ohosLoglevel, LOG_DOMAIN, "HMG_LOG", "%{public}s", buff);
|
||||
#else
|
||||
fputs(buff, stdout);
|
||||
#endif
|
||||
#if CC_REMOTE_LOG
|
||||
logRemote(buff);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
79
cocos/base/Log.h
Normal file
79
cocos/base/Log.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
enum class LogType {
|
||||
KERNEL,
|
||||
SCRIPT,
|
||||
COUNT,
|
||||
};
|
||||
|
||||
enum class LogLevel {
|
||||
FATAL,
|
||||
ERR,
|
||||
WARN,
|
||||
INFO,
|
||||
LEVEL_DEBUG, // DEBUG is a macro on windows, so use LEVEL_DEBUG instead.
|
||||
COUNT,
|
||||
};
|
||||
|
||||
class CC_DLL Log {
|
||||
public:
|
||||
static LogLevel slogLevel; // for read only
|
||||
|
||||
static inline void setLogLevel(LogLevel level) { slogLevel = level; }
|
||||
static inline FILE *getLogFile() { return slogFile; }
|
||||
static void setLogFile(const ccstd::string &filename);
|
||||
static void close();
|
||||
static void logMessage(LogType type, LogLevel level, const char *formats, ...);
|
||||
|
||||
private:
|
||||
static void logRemote(const char *msg);
|
||||
static FILE *slogFile;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#define CC_LOG_DEBUG(formats, ...) \
|
||||
if (cc::Log::slogLevel >= cc::LogLevel::LEVEL_DEBUG) cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::LEVEL_DEBUG, formats, ##__VA_ARGS__)
|
||||
#define CC_LOG_INFO(formats, ...) \
|
||||
if (cc::Log::slogLevel >= cc::LogLevel::INFO) cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::INFO, formats, ##__VA_ARGS__)
|
||||
#define CC_LOG_WARNING(formats, ...) \
|
||||
if (cc::Log::slogLevel >= cc::LogLevel::WARN) cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::WARN, formats, ##__VA_ARGS__)
|
||||
#define DO_CC_LOG_ERROR(formats, ...) \
|
||||
if (cc::Log::slogLevel >= cc::LogLevel::ERR) cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::ERR, formats, ##__VA_ARGS__)
|
||||
#define CC_LOG_FATAL(formats, ...) \
|
||||
if (cc::Log::slogLevel >= cc::LogLevel::FATAL) cc::Log::logMessage(cc::LogType::KERNEL, cc::LogLevel::FATAL, formats, ##__VA_ARGS__)
|
||||
|
||||
#define CC_LOG_ERROR(formats, ...) \
|
||||
do { \
|
||||
DO_CC_LOG_ERROR("[ERROR] file %s: line %d ", __FILE__, __LINE__); \
|
||||
DO_CC_LOG_ERROR(formats, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
336
cocos/base/LogRemote.cpp
Normal file
336
cocos/base/LogRemote.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Log.h"
|
||||
|
||||
#if CC_REMOTE_LOG
|
||||
#include <chrono>
|
||||
#include <sstream>
|
||||
#include <string_view>
|
||||
#include "platform/FileUtils.h"
|
||||
#include "rapidjson/document.h"
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <cstdio>
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// #define AUTO_TEST_CONFIG_FILE "auto-test-config.json" // v1
|
||||
#define AUTO_TEST_CONFIG_FILE "testConfig.json" // v2
|
||||
|
||||
#define OLD_ATC_KEY_CONFIG "ServerConfig"
|
||||
#define OLD_ATC_KEY_IP "IP"
|
||||
#define OLD_ATC_KEY_PORT "PORT"
|
||||
#define OLD_ATC_KEY_PLANID "planId"
|
||||
#define OLD_ATC_KEY_FLAGID "flagId"
|
||||
|
||||
#define ATC_KEY_CONFIG "localServer"
|
||||
#define ATC_KEY_IP "ip"
|
||||
#define ATC_KEY_PORT "port"
|
||||
#define ATC_KEY_JOBID "jobId"
|
||||
#define ATC_KEY_PLATFORMS "platforms"
|
||||
#define ATC_KEY_PLATFORM_INDEX "platformIndex"
|
||||
|
||||
enum class UdpLogClientState {
|
||||
UNINITIALIZED,
|
||||
INITIALIZED,
|
||||
CONFIGURED,
|
||||
OK,
|
||||
DONE, // FAILED
|
||||
};
|
||||
|
||||
uint64_t logId = 0;
|
||||
|
||||
/**
|
||||
* Parse auto-test-config.json to get ServerConfig.IP & ServerConfig.PORT
|
||||
* Logs will be formated with 5 fields
|
||||
* 1. testId
|
||||
* 2. clientId
|
||||
* 3. bootId, the boot timestamp
|
||||
* 4. sequence number of the message
|
||||
* 5. log content
|
||||
*
|
||||
* These parts are joined with '\n'.
|
||||
*
|
||||
* The log text is sent to the server via UDP. Due to the nature of the UDP protocol,
|
||||
* there may be packet loss/missequencing issues.
|
||||
*/
|
||||
class UdpLogClient {
|
||||
public:
|
||||
UdpLogClient() {
|
||||
init();
|
||||
tryParseConfig();
|
||||
}
|
||||
|
||||
~UdpLogClient() {
|
||||
deinit();
|
||||
}
|
||||
|
||||
void sendFullLog(const std::string_view &msg) {
|
||||
if (_status == UdpLogClientState::DONE) {
|
||||
return;
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << _testID << std::endl
|
||||
<< _clientID << std::endl
|
||||
<< _bootID << std::endl
|
||||
<< ++logId << std::endl
|
||||
<< msg;
|
||||
sendLog(ss.str());
|
||||
}
|
||||
|
||||
private:
|
||||
void init() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
WSAData wsa;
|
||||
if (WSAStartup(MAKEWORD(1, 2), &wsa) != 0) {
|
||||
printf("WSAStartup failed, code: %d\n", WSAGetLastError());
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_status = UdpLogClientState::INITIALIZED;
|
||||
}
|
||||
|
||||
void deinit() {
|
||||
if (_status == UdpLogClientState::OK) {
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
closesocket(_sock);
|
||||
WSACleanup();
|
||||
#else
|
||||
close(_sock);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void tryParseConfig() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
if (_status != UdpLogClientState::INITIALIZED) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
auto *fu = cc::FileUtils::getInstance();
|
||||
if (!fu) {
|
||||
// engine is not ready, retry later
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fu->isFileExist(AUTO_TEST_CONFIG_FILE)) {
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
auto content = fu->getStringFromFile(AUTO_TEST_CONFIG_FILE);
|
||||
rapidjson::Document doc;
|
||||
doc.Parse(content.c_str(), content.length());
|
||||
|
||||
if (doc.HasParseError()) {
|
||||
auto code = doc.GetParseError();
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (doc.HasMember(OLD_ATC_KEY_CONFIG)) {
|
||||
// parse clientID & testID
|
||||
if (doc.HasMember(OLD_ATC_KEY_FLAGID)) {
|
||||
_clientID = doc[OLD_ATC_KEY_FLAGID].GetString();
|
||||
} else {
|
||||
_clientID = "flagId is not set!";
|
||||
}
|
||||
|
||||
if (doc.HasMember(OLD_ATC_KEY_PLANID)) {
|
||||
_testID = doc[OLD_ATC_KEY_PLANID].GetString();
|
||||
} else {
|
||||
_testID = "planId is not set!";
|
||||
}
|
||||
|
||||
// parse ip & port
|
||||
rapidjson::Value &cfg = doc[OLD_ATC_KEY_CONFIG];
|
||||
if (!cfg.HasMember(OLD_ATC_KEY_IP) || !cfg.HasMember(OLD_ATC_KEY_PORT)) {
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
const char *remoteIp = cfg[OLD_ATC_KEY_IP].GetString();
|
||||
// The `PORT` property is used by other service and the next port is for log collection.
|
||||
int remotePort = cfg[OLD_ATC_KEY_PORT].GetInt() + 1;
|
||||
setServerAddr(remoteIp, remotePort);
|
||||
} else if (doc.HasMember(ATC_KEY_CONFIG)) {
|
||||
if (doc.HasMember(ATC_KEY_JOBID)) {
|
||||
_testID = doc[ATC_KEY_JOBID].GetString();
|
||||
} else {
|
||||
_testID = "jobId is not set!";
|
||||
}
|
||||
if (doc.HasMember(ATC_KEY_PLATFORMS)) {
|
||||
rapidjson::Value &platforms = doc[ATC_KEY_PLATFORMS];
|
||||
if (!platforms.IsArray() || platforms.Size() < 1) {
|
||||
_clientID = "array platforms is empty";
|
||||
} else {
|
||||
rapidjson::Value &plt = platforms[0];
|
||||
if (!plt.HasMember(ATC_KEY_PLATFORM_INDEX)) {
|
||||
_clientID = "platforms[0] not key platformIndex";
|
||||
} else {
|
||||
rapidjson::Value &index = plt[ATC_KEY_PLATFORM_INDEX];
|
||||
_clientID = index.IsInt() ? std::to_string(index.GetInt()) : index.GetString();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_clientID = "platforms not set!";
|
||||
}
|
||||
|
||||
// parse ip & port
|
||||
rapidjson::Value &cfg = doc[ATC_KEY_CONFIG];
|
||||
if (!cfg.HasMember(ATC_KEY_IP) || !cfg.HasMember(ATC_KEY_PORT)) {
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
const char *remoteIp = cfg[ATC_KEY_IP].GetString();
|
||||
// The `PORT` property is used by other service and the next port is for log collection.
|
||||
int remotePort = cfg[ATC_KEY_PORT].GetInt() + 1;
|
||||
setServerAddr(remoteIp, remotePort);
|
||||
} else {
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
_bootID = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
|
||||
_status = UdpLogClientState::CONFIGURED;
|
||||
}
|
||||
|
||||
void setServerAddr(const std::string_view &addr, int port) {
|
||||
memset(&_serverAddr, 0, sizeof(_serverAddr));
|
||||
_serverAddr.sin_family = AF_INET;
|
||||
_serverAddr.sin_addr.s_addr = inet_addr(addr.data());
|
||||
_serverAddr.sin_port = htons(port);
|
||||
}
|
||||
|
||||
static auto getErrorCode() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ensureInitSocket() {
|
||||
if (_status == UdpLogClientState::INITIALIZED) {
|
||||
tryParseConfig();
|
||||
}
|
||||
if (_status != UdpLogClientState::CONFIGURED) {
|
||||
return;
|
||||
}
|
||||
memset(&_localAddr, 0, sizeof(_localAddr));
|
||||
_localAddr.sin_family = AF_INET;
|
||||
_localAddr.sin_addr.s_addr = INADDR_ANY;
|
||||
_localAddr.sin_port = 0; // bind random port
|
||||
|
||||
if ((_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||
auto errorCode = getErrorCode();
|
||||
_status = UdpLogClientState::DONE;
|
||||
printf("create socket failed, code: %d\n", errorCode);
|
||||
return;
|
||||
}
|
||||
if (bind(_sock, reinterpret_cast<sockaddr *>(&_localAddr), sizeof(_localAddr))) {
|
||||
_status = UdpLogClientState::DONE;
|
||||
auto errorCode = getErrorCode();
|
||||
printf("bind socket failed, code: %d\n", errorCode);
|
||||
return;
|
||||
}
|
||||
if (connect(_sock, reinterpret_cast<sockaddr *>(&_serverAddr), sizeof(_serverAddr))) {
|
||||
auto errorCode = getErrorCode();
|
||||
printf("connect socket failed, code: %d\n", errorCode);
|
||||
_status = UdpLogClientState::DONE;
|
||||
return;
|
||||
}
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
u_long mode = 1;
|
||||
if (ioctlsocket(_sock, FIONBIO, &mode)) {
|
||||
auto errorCode = getErrorCode();
|
||||
printf("set nonblock failed, code: %d\n", errorCode);
|
||||
// continue
|
||||
}
|
||||
#else
|
||||
int flags = fcntl(_sock, F_GETFL);
|
||||
if (fcntl(_sock, F_SETFL, flags | O_NONBLOCK)) {
|
||||
auto errorCode = getErrorCode();
|
||||
printf("set nonblock failed, code: %d\n", errorCode);
|
||||
// continue
|
||||
}
|
||||
#endif
|
||||
_status = UdpLogClientState::OK;
|
||||
}
|
||||
|
||||
void sendLog(const std::string_view &msg) {
|
||||
ensureInitSocket();
|
||||
if (_status == UdpLogClientState::OK) {
|
||||
send(_sock, msg.data(), msg.size(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
SOCKET _sock{INVALID_SOCKET};
|
||||
#else
|
||||
int _sock{-1};
|
||||
#endif
|
||||
sockaddr_in _serverAddr;
|
||||
sockaddr_in _localAddr;
|
||||
UdpLogClientState _status{UdpLogClientState::UNINITIALIZED};
|
||||
std::string _testID;
|
||||
std::string _clientID;
|
||||
uint64_t _bootID{0};
|
||||
};
|
||||
|
||||
void sendLogThroughUDP(const std::string_view &msg) {
|
||||
static UdpLogClient remote;
|
||||
remote.sendFullLog(msg);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
void Log::logRemote(const char *msg) {
|
||||
#if CC_REMOTE_LOG
|
||||
sendLogThroughUDP(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
411
cocos/base/Macros.h
Normal file
411
cocos/base/Macros.h
Normal file
@@ -0,0 +1,411 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // To include uint8_t, uint16_t and so on.
|
||||
|
||||
#include "Assertf.h"
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#if defined(CC_STATIC)
|
||||
#define CC_DLL
|
||||
#else
|
||||
#if defined(_USRDLL)
|
||||
#define CC_DLL __declspec(dllexport)
|
||||
#else /* use a DLL library */
|
||||
#define CC_DLL __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define CC_DLL
|
||||
#endif
|
||||
|
||||
/** @def CC_DEGREES_TO_RADIANS
|
||||
converts degrees to radians
|
||||
*/
|
||||
#define CC_DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__)*0.01745329252f) // PI / 180
|
||||
|
||||
/** @def CC_RADIANS_TO_DEGREES
|
||||
converts radians to degrees
|
||||
*/
|
||||
#define CC_RADIANS_TO_DEGREES(__ANGLE__) ((__ANGLE__)*57.29577951f) // PI * 180
|
||||
|
||||
#ifndef FLT_EPSILON
|
||||
#define FLT_EPSILON 1.192092896e-07F
|
||||
#endif // FLT_EPSILON
|
||||
|
||||
/**
|
||||
Helper macros which converts 4-byte little/big endian
|
||||
integral number to the machine native number representation
|
||||
|
||||
It should work same as apples CFSwapInt32LittleToHost(..)
|
||||
*/
|
||||
|
||||
/// when define returns true it means that our architecture uses big endian
|
||||
#define CC_HOST_IS_BIG_ENDIAN (bool)(*(unsigned short *)"\0\xff" < 0x100)
|
||||
#define CC_SWAP32(i) ((i & 0x000000ff) << 24 | (i & 0x0000ff00) << 8 | (i & 0x00ff0000) >> 8 | (i & 0xff000000) >> 24)
|
||||
#define CC_SWAP16(i) ((i & 0x00ff) << 8 | (i & 0xff00) >> 8)
|
||||
#define CC_SWAP_INT32_LITTLE_TO_HOST(i) ((CC_HOST_IS_BIG_ENDIAN == true) ? CC_SWAP32(i) : (i))
|
||||
#define CC_SWAP_INT16_LITTLE_TO_HOST(i) ((CC_HOST_IS_BIG_ENDIAN == true) ? CC_SWAP16(i) : (i))
|
||||
#define CC_SWAP_INT32_BIG_TO_HOST(i) ((CC_HOST_IS_BIG_ENDIAN == true) ? (i) : CC_SWAP32(i))
|
||||
#define CC_SWAP_INT16_BIG_TO_HOST(i) ((CC_HOST_IS_BIG_ENDIAN == true) ? (i) : CC_SWAP16(i))
|
||||
|
||||
// new callbacks based on C++11
|
||||
#define CC_CALLBACK_0(__selector__, __target__, ...) std::bind(&__selector__, __target__, ##__VA_ARGS__)
|
||||
#define CC_CALLBACK_1(__selector__, __target__, ...) std::bind(&__selector__, __target__, std::placeholders::_1, ##__VA_ARGS__)
|
||||
#define CC_CALLBACK_2(__selector__, __target__, ...) std::bind(&__selector__, __target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
|
||||
#define CC_CALLBACK_3(__selector__, __target__, ...) std::bind(&__selector__, __target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
|
||||
|
||||
// Generic macros
|
||||
|
||||
#define CC_BREAK_IF(cond) \
|
||||
if (cond) break
|
||||
|
||||
/** @def CC_DEPRECATED_ATTRIBUTE
|
||||
* Only certain compilers support __attribute__((deprecated)).
|
||||
*/
|
||||
#if defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)))
|
||||
#define CC_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
|
||||
#elif _MSC_VER >= 1400 // vs 2005 or higher
|
||||
#define CC_DEPRECATED_ATTRIBUTE __declspec(deprecated)
|
||||
#else
|
||||
#define CC_DEPRECATED_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
/** @def CC_DEPRECATED(...)
|
||||
* Macro to mark things deprecated as of a particular version
|
||||
* can be used with arbitrary parameters which are thrown away.
|
||||
* e.g. CC_DEPRECATED(4.0) or CC_DEPRECATED(4.0, "not going to need this anymore") etc.
|
||||
*/
|
||||
#define CC_DEPRECATED(...) CC_DEPRECATED_ATTRIBUTE
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define CC_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define CC_UNUSED
|
||||
#endif
|
||||
|
||||
#define CC_UNUSED_PARAM(unusedparam) (void)unusedparam
|
||||
|
||||
/** @def CC_FORMAT_PRINTF(formatPos, argPos)
|
||||
* Only certain compiler support __attribute__((format))
|
||||
*
|
||||
* @param formatPos 1-based position of format string argument.
|
||||
* @param argPos 1-based position of first format-dependent argument.
|
||||
*/
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 4)
|
||||
#define CC_FORMAT_PRINTF(formatPos, argPos) __attribute__((__format__(printf, formatPos, argPos)))
|
||||
#elif defined(__has_attribute)
|
||||
#if __has_attribute(format)
|
||||
#define CC_FORMAT_PRINTF(formatPos, argPos) __attribute__((__format__(printf, formatPos, argPos)))
|
||||
#else
|
||||
#define CC_FORMAT_PRINTF(formatPos, argPos)
|
||||
#endif // __has_attribute(format)
|
||||
#else
|
||||
#define CC_FORMAT_PRINTF(formatPos, argPos)
|
||||
#endif
|
||||
|
||||
// Initial compiler-related stuff to set.
|
||||
#define CC_COMPILER_MSVC 1
|
||||
#define CC_COMPILER_CLANG 2
|
||||
#define CC_COMPILER_GNUC 3
|
||||
|
||||
// CPU Architecture
|
||||
#define CC_CPU_UNKNOWN 0
|
||||
#define CC_CPU_X86 1
|
||||
#define CC_CPU_PPC 2
|
||||
#define CC_CPU_ARM 3
|
||||
#define CC_CPU_MIPS 4
|
||||
|
||||
// 32-bits or 64-bits CPU
|
||||
#define CC_CPU_ARCH_32 1
|
||||
#define CC_CPU_ARCH_64 2
|
||||
|
||||
// Mode
|
||||
#define CC_MODE_DEBUG 1
|
||||
#define CC_MODE_RELEASE 2
|
||||
|
||||
// Compiler type and version recognition
|
||||
#if defined(_MSC_VER)
|
||||
#define CC_COMPILER CC_COMPILER_MSVC
|
||||
#elif defined(__clang__)
|
||||
#define CC_COMPILER CC_COMPILER_CLANG
|
||||
#elif defined(__GNUC__)
|
||||
#define CC_COMPILER CC_COMPILER_GNUC
|
||||
#else
|
||||
#error "Unknown compiler. Abort!"
|
||||
#endif
|
||||
|
||||
#if INTPTR_MAX == INT32_MAX
|
||||
#define CC_CPU_ARCH CC_CPU_ARCH_32
|
||||
#else
|
||||
#define CC_CPU_ARCH CC_CPU_ARCH_64
|
||||
#endif
|
||||
|
||||
#if defined(__arm64__) || defined(__aarch64__)
|
||||
#define CC_ARCH_ARM64 1
|
||||
#else
|
||||
#define CC_ARCH_ARM64 0
|
||||
#endif
|
||||
|
||||
// CC_HAS_ARM64_FP16 set to 1 if the architecture provides an IEEE compliant ARM fp16 type
|
||||
#if CC_ARCH_ARM64
|
||||
#ifndef CC_HAS_ARM64_FP16
|
||||
#if defined(__ARM_FP16_FORMAT_IEEE)
|
||||
#define CC_HAS_ARM64_FP16 1
|
||||
#else
|
||||
#define CC_HAS_ARM64_FP16 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// CC_HAS_ARM64_FP16_VECTOR_ARITHMETIC set to 1 if the architecture supports Neon vector intrinsics for fp16.
|
||||
#if CC_ARCH_ARM64
|
||||
#ifndef CC_HAS_ARM64_FP16_VECTOR_ARITHMETIC
|
||||
#if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
|
||||
#define CC_HAS_ARM64_FP16_VECTOR_ARITHMETIC 1
|
||||
#else
|
||||
#define CC_HAS_ARM64_FP16_VECTOR_ARITHMETIC 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC set to 1 if the architecture supports Neon scalar intrinsics for fp16.
|
||||
#if CC_ARCH_ARM64
|
||||
#ifndef CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC
|
||||
#if defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC)
|
||||
#define CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC 1
|
||||
#else
|
||||
#define CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC 0
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Disable MSVC warning
|
||||
#if (CC_COMPILER == CC_COMPILER_MSVC)
|
||||
#pragma warning(disable : 4251 4275 4819)
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
#ifndef _SCL_SECURE_NO_DEPRECATE
|
||||
#define _SCL_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define CC_CACHELINE_SIZE 64
|
||||
|
||||
#if (CC_COMPILER == CC_COMPILER_MSVC)
|
||||
// MSVC ENABLE/DISABLE WARNING DEFINITION
|
||||
#define CC_DISABLE_WARNINGS() \
|
||||
__pragma(warning(push, 0))
|
||||
|
||||
#define CC_ENABLE_WARNINGS() \
|
||||
__pragma(warning(pop))
|
||||
#elif (CC_COMPILER == CC_COMPILER_GNUC)
|
||||
// GCC ENABLE/DISABLE WARNING DEFINITION
|
||||
#define CC_DISABLE_WARNINGS() \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wall\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wextra\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtautological-compare\"")
|
||||
|
||||
#define CC_ENABLE_WARNINGS() \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#elif (CC_COMPILER == CC_COMPILER_CLANG)
|
||||
// CLANG ENABLE/DISABLE WARNING DEFINITION
|
||||
#define CC_DISABLE_WARNINGS() \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wall\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wextra\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtautological-compare\"")
|
||||
|
||||
#define CC_ENABLE_WARNINGS() \
|
||||
_Pragma("clang diagnostic pop")
|
||||
#endif
|
||||
|
||||
#define CC_DISALLOW_ASSIGN(TypeName) \
|
||||
TypeName &operator=(const TypeName &) = delete; \
|
||||
TypeName &operator=(TypeName &&) = delete;
|
||||
|
||||
#define CC_DISALLOW_COPY_MOVE_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName &) = delete; \
|
||||
TypeName(TypeName &&) = delete; \
|
||||
CC_DISALLOW_ASSIGN(TypeName)
|
||||
|
||||
#if (CC_COMPILER == CC_COMPILER_MSVC)
|
||||
#define CC_ALIGN(N) __declspec(align(N))
|
||||
#define CC_CACHE_ALIGN __declspec(align(CC_CACHELINE_SIZE))
|
||||
#define CC_PACKED_ALIGN(N) __declspec(align(N))
|
||||
|
||||
#define CC_ALIGNED_DECL(type, var, alignment) __declspec(align(alignment)) type var
|
||||
|
||||
#define CC_READ_COMPILER_BARRIER() _ReadBarrier()
|
||||
#define CC_WRITE_COMPILER_BARRIER() _WriteBarrier()
|
||||
#define CC_COMPILER_BARRIER() _ReadWriteBarrier()
|
||||
|
||||
#define CC_READ_MEMORY_BARRIER() MemoryBarrier()
|
||||
#define CC_WRITE_MEMORY_BARRIER() MemoryBarrier()
|
||||
#define CC_MEMORY_BARRIER() MemoryBarrier()
|
||||
|
||||
#define CC_CPU_READ_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm { lfence} \
|
||||
} while (0)
|
||||
#define CC_CPU_WRITE_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm { sfence} \
|
||||
} while (0)
|
||||
#define CC_CPU_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm { mfence} \
|
||||
} while (0)
|
||||
|
||||
#elif (CC_COMPILER == CC_COMPILER_GNUC) || (CC_COMPILER == CC_COMPILER_CLANG)
|
||||
#define CC_ALIGN(N) __attribute__((__aligned__((N))))
|
||||
#define CC_CACHE_ALIGN __attribute__((__aligned__((CC_CACHELINE_SIZE))))
|
||||
#define CC_PACKED_ALIGN(N) __attribute__((packed, aligned(N)))
|
||||
|
||||
#define CC_ALIGNED_DECL(type, var, alignment) type var __attribute__((__aligned__(alignment)))
|
||||
|
||||
#define CC_READ_COMPILER_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
#define CC_WRITE_COMPILER_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
#define CC_COMPILER_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#define CC_READ_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__sync_synchronize(); \
|
||||
} while (0)
|
||||
#define CC_WRITE_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__sync_synchronize(); \
|
||||
} while (0)
|
||||
#define CC_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__sync_synchronize(); \
|
||||
} while (0)
|
||||
|
||||
#define CC_CPU_READ_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("lfence" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
#define CC_CPU_WRITE_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("sfence" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
#define CC_CPU_MEMORY_BARRIER() \
|
||||
do { \
|
||||
__asm__ __volatile__("mfence" \
|
||||
: \
|
||||
: \
|
||||
: "memory"); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
#error "Unsupported compiler!"
|
||||
#endif
|
||||
|
||||
/* Stack-alignment
|
||||
If macro __CC_SIMD_ALIGN_STACK defined, means there requests
|
||||
special code to ensure stack align to a 16-bytes boundary.
|
||||
|
||||
Note:
|
||||
This macro can only guarantee callee stack pointer (esp) align
|
||||
to a 16-bytes boundary, but not that for frame pointer (ebp).
|
||||
Because most compiler might use frame pointer to access to stack
|
||||
variables, so you need to wrap those alignment required functions
|
||||
with extra function call.
|
||||
*/
|
||||
#if defined(__INTEL_COMPILER)
|
||||
// For intel's compiler, simply calling alloca seems to do the right
|
||||
// thing. The size of the allocated block seems to be irrelevant.
|
||||
#define CC_SIMD_ALIGN_STACK() _alloca(16)
|
||||
#define CC_SIMD_ALIGN_ATTRIBUTE
|
||||
|
||||
#elif (CC_CPU == CC_CPU_X86) && (CC_COMPILER == CC_COMPILER_GNUC || CC_COMPILER == CC_COMPILER_CLANG) && (CC_CPU_ARCH != CC_CPU_ARCH_64)
|
||||
// mark functions with GCC attribute to force stack alignment to 16 bytes
|
||||
#define CC_SIMD_ALIGN_ATTRIBUTE __attribute__((force_align_arg_pointer))
|
||||
#elif (CC_COMPILER == CC_COMPILER_MSVC)
|
||||
// Fortunately, MSVC will align the stack automatically
|
||||
#define CC_SIMD_ALIGN_ATTRIBUTE
|
||||
#else
|
||||
#define CC_SIMD_ALIGN_ATTRIBUTE
|
||||
#endif
|
||||
|
||||
// mode
|
||||
#if (defined(_DEBUG) || defined(DEBUG)) && (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#define CC_MODE CC_MODE_DEBUG
|
||||
#else
|
||||
#define CC_MODE CC_MODE_RELEASE
|
||||
#endif
|
||||
|
||||
#define CC_TOSTR(s) #s
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define CC_PREDICT_TRUE(x) __builtin_expect(!!(x), 1)
|
||||
#define CC_PREDICT_FALSE(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define CC_PREDICT_TRUE(x) (x)
|
||||
#define CC_PREDICT_FALSE(x) (x)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define CC_FORCE_INLINE __forceinline
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define CC_FORCE_INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
#if defined(__cplusplus) || defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
#define CC_FORCE_INLINE static inline
|
||||
#elif
|
||||
#define CC_FORCE_INLINE inline
|
||||
#endif
|
||||
#endif
|
||||
35
cocos/base/Object.h
Executable file
35
cocos/base/Object.h
Executable file
@@ -0,0 +1,35 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Object {
|
||||
public:
|
||||
Object() = default;
|
||||
virtual ~Object() = default;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
226
cocos/base/Ptr.h
Normal file
226
cocos/base/Ptr.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// Originally the class is from WebRTC.
|
||||
// https://chromium.googlesource.com/external/webrtc/+/master/api/scoped_refptr.h
|
||||
//
|
||||
|
||||
// A smart pointer class for reference counted objects. Use this class instead
|
||||
// of calling addRef and Release manually on a reference counted object to
|
||||
// avoid common memory leaks caused by forgetting to Release an object
|
||||
// reference. Sample usage:
|
||||
//
|
||||
// class MyFoo : public RefCounted<MyFoo> {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// void some_function() {
|
||||
// IntrusivePtr<MyFoo> foo = ccnew MyFoo();
|
||||
// foo->Method(param);
|
||||
// // `foo` is released when this function returns
|
||||
// }
|
||||
//
|
||||
// void some_other_function() {
|
||||
// IntrusivePtr<MyFoo> foo = ccnew MyFoo();
|
||||
// ...
|
||||
// foo = nullptr; // explicitly releases `foo`
|
||||
// ...
|
||||
// if (foo)
|
||||
// foo->Method(param);
|
||||
// }
|
||||
//
|
||||
// The above examples show how IntrusivePtr<T> acts like a pointer to T.
|
||||
// Given two IntrusivePtr<T> classes, it is also possible to exchange
|
||||
// references between the two objects, like so:
|
||||
//
|
||||
// {
|
||||
// IntrusivePtr<MyFoo> a = ccnew MyFoo();
|
||||
// IntrusivePtr<MyFoo> b;
|
||||
//
|
||||
// b.swap(a);
|
||||
// // now, `b` references the MyFoo object, and `a` references null.
|
||||
// }
|
||||
//
|
||||
// To make both `a` and `b` in the above example reference the same MyFoo
|
||||
// object, simply use the assignment operator:
|
||||
//
|
||||
// {
|
||||
// IntrusivePtr<MyFoo> a = ccnew MyFoo();
|
||||
// IntrusivePtr<MyFoo> b;
|
||||
//
|
||||
// b = a;
|
||||
// // now, `a` and `b` each own a reference to the same MyFoo object.
|
||||
// }
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "cocos/base/std/hash/hash_fwd.hpp"
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <class T>
|
||||
class IntrusivePtr {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
IntrusivePtr() {
|
||||
}
|
||||
|
||||
IntrusivePtr(T *p) : _ptr(p) { // NOLINT
|
||||
if (_ptr) {
|
||||
_ptr->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
IntrusivePtr(const IntrusivePtr<T> &r) : _ptr(r._ptr) {
|
||||
if (_ptr) {
|
||||
_ptr->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr(const IntrusivePtr<U> &r) : _ptr(r.get()) { // NOLINT
|
||||
if (_ptr) {
|
||||
_ptr->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
// Move constructors.
|
||||
IntrusivePtr(IntrusivePtr<T> &&r) noexcept : _ptr(r.release()) {
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr(IntrusivePtr<U> &&r) noexcept : _ptr(r.release()) { // NOLINT
|
||||
}
|
||||
|
||||
~IntrusivePtr() {
|
||||
if (_ptr) {
|
||||
_ptr->release();
|
||||
}
|
||||
}
|
||||
|
||||
T *get() const { return _ptr; }
|
||||
operator T *() const { return _ptr; } // NOLINT
|
||||
T &operator*() const { return *_ptr; }
|
||||
T *operator->() const { return _ptr; }
|
||||
|
||||
// As reference count is 1 after creating a RefCounted object, so do not have to
|
||||
// invoke p->addRef();
|
||||
IntrusivePtr<T> &operator=(T *p) {
|
||||
reset(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntrusivePtr<T> &operator=(const IntrusivePtr<T> &r) { // NOLINT
|
||||
return *this = r._ptr; // NOLINT
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr<T> &operator=(const IntrusivePtr<U> &r) {
|
||||
return *this = r.get(); // NOLINT
|
||||
}
|
||||
|
||||
IntrusivePtr<T> &operator=(IntrusivePtr<T> &&r) noexcept {
|
||||
IntrusivePtr<T>(std::move(r)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
IntrusivePtr<T> &operator=(IntrusivePtr<U> &&r) noexcept {
|
||||
IntrusivePtr<T>(std::move(r)).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(std::nullptr_t) {
|
||||
return _ptr == nullptr;
|
||||
}
|
||||
|
||||
bool operator==(T *r) {
|
||||
return _ptr == r;
|
||||
}
|
||||
|
||||
bool operator!=(std::nullptr_t) {
|
||||
return _ptr != nullptr;
|
||||
}
|
||||
|
||||
bool operator!=(T *r) {
|
||||
return _ptr != r;
|
||||
}
|
||||
|
||||
void reset() noexcept {
|
||||
if (_ptr) {
|
||||
_ptr->release();
|
||||
}
|
||||
_ptr = nullptr;
|
||||
}
|
||||
|
||||
void reset(T *p) {
|
||||
// AddRef first so that self assignment should work
|
||||
if (p) {
|
||||
p->addRef();
|
||||
}
|
||||
if (_ptr) {
|
||||
_ptr->release();
|
||||
}
|
||||
_ptr = p;
|
||||
}
|
||||
|
||||
void swap(T **pp) noexcept {
|
||||
T *p = _ptr;
|
||||
_ptr = *pp;
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
void swap(IntrusivePtr<T> &r) noexcept { swap(&r._ptr); }
|
||||
|
||||
private:
|
||||
// Returns the (possibly null) raw pointer, and makes the scoped_refptr hold a
|
||||
// null pointer, all without touching the reference count of the underlying
|
||||
// pointed-to object. The object is still reference counted, and the caller of
|
||||
// release() is now the proud owner of one reference, so it is responsible for
|
||||
// calling Release() once on the object when no longer using it.
|
||||
T *release() {
|
||||
T *retVal = _ptr;
|
||||
_ptr = nullptr;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected:
|
||||
T *_ptr{nullptr};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
template <class T>
|
||||
struct hash<cc::IntrusivePtr<T>> {
|
||||
hash_t operator()(const cc::IntrusivePtr<T> &val) const noexcept {
|
||||
return hash<T *>{}(val.get());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ccstd
|
||||
122
cocos/base/Random.h
Normal file
122
cocos/base/Random.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <random>
|
||||
|
||||
#include "base/Macros.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* @class RandomHelper
|
||||
* @brief A helper class for creating random number.
|
||||
*/
|
||||
class CC_DLL RandomHelper {
|
||||
public:
|
||||
template <typename T>
|
||||
static inline T randomReal(T min, T max) {
|
||||
std::uniform_real_distribution<T> dist(min, max);
|
||||
auto &mt = RandomHelper::getEngine();
|
||||
return dist(mt);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T randomInt(T min, T max) {
|
||||
std::uniform_int_distribution<T> dist(min, max);
|
||||
auto &mt = RandomHelper::getEngine();
|
||||
return dist(mt);
|
||||
}
|
||||
|
||||
private:
|
||||
static inline std::mt19937 &getEngine() {
|
||||
static std::random_device seedGen;
|
||||
static std::mt19937 engine(seedGen());
|
||||
return engine;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a random value between `min` and `max`.
|
||||
*/
|
||||
template <typename T>
|
||||
inline T random(T min, T max) {
|
||||
return RandomHelper::randomInt<T>(min, max);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline float random(float min, float max) {
|
||||
return RandomHelper::randomReal(min, max);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long double random(long double min, long double max) {
|
||||
return RandomHelper::randomReal(min, max);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double random(double min, double max) {
|
||||
return RandomHelper::randomReal(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random int between 0 and RAND_MAX.
|
||||
*/
|
||||
inline int random() {
|
||||
return cc::random(0, static_cast<int>(RAND_MAX));
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a random float between -1 and 1.
|
||||
* It can be seeded using std::srand(seed);
|
||||
*/
|
||||
inline float randMinus1_1() {
|
||||
// IDEA: using the new c++11 random engine generator
|
||||
// without a proper way to set a seed is not useful.
|
||||
// Resorting to the old random method since it can
|
||||
// be seeded using std::srand()
|
||||
return ((std::rand() / (float)RAND_MAX) * 2) - 1;
|
||||
|
||||
// return cc::random(-1.f, 1.f);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a random float between 0 and 1.
|
||||
* It can be seeded using std::srand(seed);
|
||||
*/
|
||||
inline float rand0_1() {
|
||||
// IDEA: using the new c++11 random engine generator
|
||||
// without a proper way to set a seed is not useful.
|
||||
// Resorting to the old random method since it can
|
||||
// be seeded using std::srand()
|
||||
return std::rand() / (float)RAND_MAX;
|
||||
|
||||
// return cc::random(0.f, 1.f);
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
109
cocos/base/RefCounted.cpp
Normal file
109
cocos/base/RefCounted.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
#include <algorithm> // std::find
|
||||
#include "base/Log.h"
|
||||
#include "base/std/container/list.h"
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
static void trackRef(RefCounted *ref);
|
||||
static void untrackRef(RefCounted *ref);
|
||||
#endif
|
||||
|
||||
RefCounted::RefCounted() { // NOLINT(modernize-use-equals-default)
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
trackRef(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
RefCounted::~RefCounted() { // NOLINT(modernize-use-equals-default)
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
untrackRef(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RefCounted::addRef() {
|
||||
++_referenceCount;
|
||||
}
|
||||
|
||||
void RefCounted::release() {
|
||||
CC_ASSERT_GT(_referenceCount, 0);
|
||||
--_referenceCount;
|
||||
|
||||
if (_referenceCount == 0) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int RefCounted::getRefCount() const {
|
||||
return _referenceCount;
|
||||
}
|
||||
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
|
||||
static ccstd::list<RefCounted *> __refAllocationList;
|
||||
|
||||
void RefCounted::printLeaks() {
|
||||
// Dump Ref object memory leaks
|
||||
if (__refAllocationList.empty()) {
|
||||
CC_LOG_INFO("[memory] All Ref objects successfully cleaned up (no leaks detected).\n");
|
||||
} else {
|
||||
CC_LOG_INFO("[memory] WARNING: %d Ref objects still active in memory.\n", (int)__refAllocationList.size());
|
||||
|
||||
for (const auto &ref : __refAllocationList) {
|
||||
CC_ASSERT(ref);
|
||||
const char *type = typeid(*ref).name();
|
||||
CC_LOG_INFO("[memory] LEAK: Ref object '%s' still active with reference count %d.\n", (type ? type : ""), ref->getRefCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void trackRef(RefCounted *ref) {
|
||||
CC_ASSERT(ref);
|
||||
|
||||
// Create memory allocation record.
|
||||
__refAllocationList.push_back(ref);
|
||||
}
|
||||
|
||||
static void untrackRef(RefCounted *ref) {
|
||||
auto iter = std::find(__refAllocationList.begin(), __refAllocationList.end(), ref);
|
||||
if (iter == __refAllocationList.end()) {
|
||||
CC_LOG_INFO("[memory] CORRUPTION: Attempting to free (%s) with invalid ref tracking record.\n", typeid(*ref).name());
|
||||
return;
|
||||
}
|
||||
|
||||
__refAllocationList.erase(iter);
|
||||
}
|
||||
|
||||
#endif // #if CC_REF_LEAK_DETECTION
|
||||
|
||||
} // namespace cc
|
||||
105
cocos/base/RefCounted.h
Normal file
105
cocos/base/RefCounted.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
|
||||
#define CC_REF_LEAK_DETECTION 0
|
||||
|
||||
namespace cc {
|
||||
|
||||
class RefCounted;
|
||||
|
||||
/**
|
||||
* Interface that defines how to clone an Ref.
|
||||
*/
|
||||
class CC_DLL Clonable {
|
||||
public:
|
||||
/** Returns a copy of the Ref. */
|
||||
virtual Clonable *clone() const = 0;
|
||||
|
||||
virtual ~Clonable() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ref is used for reference count management. If a class inherits from Ref,
|
||||
* then it is easy to be shared in different places.
|
||||
*/
|
||||
class CC_DLL RefCounted {
|
||||
public:
|
||||
virtual ~RefCounted();
|
||||
|
||||
/**
|
||||
* Retains the ownership.
|
||||
*
|
||||
* This increases the Ref's reference count.
|
||||
*
|
||||
* @see release, autorelease
|
||||
*/
|
||||
void addRef();
|
||||
|
||||
/**
|
||||
* Releases the ownership immediately.
|
||||
*
|
||||
* This decrements the Ref's reference count.
|
||||
*
|
||||
* If the reference count reaches 0 after the decrement, this Ref is
|
||||
* destructed.
|
||||
*
|
||||
* @see retain, autorelease
|
||||
*/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Returns the Ref's current reference count.
|
||||
*
|
||||
* @returns The Ref's reference count.
|
||||
*/
|
||||
unsigned int getRefCount() const;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* The Ref's reference count is 1 after construction.
|
||||
*/
|
||||
RefCounted();
|
||||
|
||||
/// count of references
|
||||
unsigned int _referenceCount{0};
|
||||
|
||||
// Memory leak diagnostic data (only included when CC_REF_LEAK_DETECTION is defined and its value isn't zero)
|
||||
#if CC_REF_LEAK_DETECTION
|
||||
public:
|
||||
static void printLeaks();
|
||||
#endif
|
||||
};
|
||||
|
||||
using SCHEDULE_CB = void (RefCounted::*)(float);
|
||||
#define CC_SCHEDULE_CALLBACK(cb) static_cast<cc::SCHEDULE_CB>(&cb)
|
||||
|
||||
} // namespace cc
|
||||
309
cocos/base/RefMap.h
Normal file
309
cocos/base/RefMap.h
Normal file
@@ -0,0 +1,309 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "base/Random.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* Similar to ccstd::unordered_map, but it will manage reference count automatically internally.
|
||||
* Which means it will invoke RefCounted::addRef() when adding an element, and invoke RefCounted::release() when removing an element.
|
||||
* @warning The element should be `RefCounted` or its sub-class.
|
||||
*/
|
||||
template <class K, class V>
|
||||
class RefMap {
|
||||
public:
|
||||
// ------------------------------------------
|
||||
// Iterators
|
||||
// ------------------------------------------
|
||||
|
||||
/** Iterator, can be used to loop the Map. */
|
||||
using iterator = typename ccstd::unordered_map<K, V>::iterator;
|
||||
/** Const iterator, can be used to loop the Map. */
|
||||
using const_iterator = typename ccstd::unordered_map<K, V>::const_iterator;
|
||||
|
||||
/** Return iterator to beginning. */
|
||||
iterator begin() { return _data.begin(); }
|
||||
/** Return const_iterator to beginning. */
|
||||
const_iterator begin() const { return _data.begin(); }
|
||||
|
||||
/** Return iterator to end.*/
|
||||
iterator end() { return _data.end(); }
|
||||
/** Return const_iterator to end.*/
|
||||
const_iterator end() const { return _data.end(); }
|
||||
|
||||
/** Return const_iterator to beginning.*/
|
||||
const_iterator cbegin() const { return _data.cbegin(); }
|
||||
/** Return const_iterator to end.*/
|
||||
const_iterator cend() const { return _data.cend(); }
|
||||
|
||||
/** Default constructor */
|
||||
RefMap<K, V>() {
|
||||
static_assert(std::is_convertible<V, RefCounted *>::value, "Invalid Type for cc::Map<K, V>!");
|
||||
}
|
||||
|
||||
/** Constructor with capacity. */
|
||||
explicit RefMap<K, V>(uint32_t capacity) {
|
||||
static_assert(std::is_convertible<V, RefCounted *>::value, "Invalid Type for cc::Map<K, V>!");
|
||||
_data.reserve(capacity);
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
RefMap<K, V>(const RefMap<K, V> &other) {
|
||||
static_assert(std::is_convertible<V, RefCounted *>::value, "Invalid Type for cc::Map<K, V>!");
|
||||
_data = other._data;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
|
||||
/** Move constructor. */
|
||||
RefMap<K, V>(RefMap<K, V> &&other) noexcept {
|
||||
static_assert(std::is_convertible<V, RefCounted *>::value, "Invalid Type for cc::Map<K, V>!");
|
||||
_data = std::move(other._data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* It will release all objects in map.
|
||||
*/
|
||||
~RefMap<K, V>() {
|
||||
clear();
|
||||
}
|
||||
|
||||
/** Sets capacity of the map. */
|
||||
void reserve(uint32_t capacity) {
|
||||
_data.reserve(capacity);
|
||||
}
|
||||
|
||||
/** Returns the number of buckets in the Map container. */
|
||||
uint32_t bucketCount() const {
|
||||
return static_cast<uint32_t>(_data.bucket_count());
|
||||
}
|
||||
|
||||
/** Returns the number of elements in bucket n. */
|
||||
uint32_t bucketSize(uint32_t n) const {
|
||||
return static_cast<uint32_t>(_data.bucket_size(n));
|
||||
}
|
||||
|
||||
/** Returns the bucket number where the element with key k is located. */
|
||||
uint32_t bucket(const K &k) const {
|
||||
return _data.bucket(k);
|
||||
}
|
||||
|
||||
/** The number of elements in the map. */
|
||||
uint32_t size() const {
|
||||
return static_cast<uint32_t>(_data.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a bool value indicating whether the map container is empty, i.e. whether its size is 0.
|
||||
* @note This function does not modify the content of the container in any way.
|
||||
* To clear the content of an array object, member function unordered_map::clear exists.
|
||||
*/
|
||||
bool empty() const {
|
||||
return _data.empty();
|
||||
}
|
||||
|
||||
/** Returns all keys in the map. */
|
||||
ccstd::vector<K> keys() const {
|
||||
ccstd::vector<K> keys;
|
||||
|
||||
if (!_data.empty()) {
|
||||
keys.reserve(_data.size());
|
||||
|
||||
for (const auto &element : _data) {
|
||||
keys.push_back(element.first);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/** Returns all keys that matches the object. */
|
||||
ccstd::vector<K> keys(V object) const {
|
||||
ccstd::vector<K> keys;
|
||||
|
||||
if (!_data.empty()) {
|
||||
keys.reserve(_data.size() / 10);
|
||||
|
||||
for (const auto &element : _data) {
|
||||
if (element.second == object) {
|
||||
keys.push_back(element.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keys.shrink_to_fit();
|
||||
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the mapped value of the element with key k in the map.
|
||||
*
|
||||
* @note If key does not match the key of any element in the container, the function return nullptr.
|
||||
* @param key Key value of the element whose mapped value is accessed.
|
||||
* Member type K is the keys for the elements in the container. defined in Map<K, V> as an alias of its first template parameter (Key).
|
||||
*/
|
||||
V at(const K &key) {
|
||||
auto iter = _data.find(key);
|
||||
if (iter != _data.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the container for an element with 'key' as key and returns an iterator to it if found,
|
||||
* otherwise it returns an iterator to Map<K, V>::end (the element past the end of the container).
|
||||
*
|
||||
* @param key Key to be searched for.
|
||||
* Member type 'K' is the type of the keys for the elements in the container,
|
||||
* defined in Map<K, V> as an alias of its first template parameter (Key).
|
||||
*/
|
||||
const_iterator find(const K &key) const {
|
||||
return _data.find(key);
|
||||
}
|
||||
|
||||
iterator find(const K &key) {
|
||||
return _data.find(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new elements in the map.
|
||||
*
|
||||
* @note If the container has already contained the key, this function will erase the old pair(key, object) and insert the new pair.
|
||||
* @param key The key to be inserted.
|
||||
* @param object The object to be inserted.
|
||||
*/
|
||||
void insert(const K &key, V object) {
|
||||
CC_ASSERT_NOT_NULL(object);
|
||||
object->addRef();
|
||||
erase(key);
|
||||
_data.insert(std::make_pair(key, object));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element with an iterator from the Map<K, V> container.
|
||||
*
|
||||
* @param position Iterator pointing to a single element to be removed from the Map<K, V>.
|
||||
* Member type const_iterator is a forward iterator type.
|
||||
*/
|
||||
iterator erase(const_iterator position) {
|
||||
CC_ASSERT(position != _data.cend());
|
||||
position->second->release();
|
||||
return _data.erase(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an element with an iterator from the Map<K, V> container.
|
||||
*
|
||||
* @param k Key of the element to be erased.
|
||||
* Member type 'K' is the type of the keys for the elements in the container,
|
||||
* defined in Map<K, V> as an alias of its first template parameter (Key).
|
||||
*/
|
||||
size_t erase(const K &k) {
|
||||
auto iter = _data.find(k);
|
||||
if (iter != _data.end()) {
|
||||
iter->second->release();
|
||||
_data.erase(iter);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes some elements with a vector which contains keys in the map.
|
||||
*
|
||||
* @param keys Keys of elements to be erased.
|
||||
*/
|
||||
void erase(const ccstd::vector<K> &keys) {
|
||||
for (const auto &key : keys) {
|
||||
this->erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All the elements in the Map<K,V> container are dropped:
|
||||
* their reference count will be decreased, and they are removed from the container,
|
||||
* leaving it with a size of 0.
|
||||
*/
|
||||
void clear() {
|
||||
for (const auto &element : _data) {
|
||||
element.second->release();
|
||||
}
|
||||
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a random object in the map.
|
||||
* @return Returns the random object if the map isn't empty, otherwise it returns nullptr.
|
||||
*/
|
||||
V getRandomObject() const {
|
||||
if (!_data.empty()) {
|
||||
auto randIdx = RandomHelper::randomInt<int>(0, static_cast<int>(_data.size()) - 1);
|
||||
const_iterator randIter = _data.begin();
|
||||
std::advance(randIter, randIdx);
|
||||
return randIter->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** Copy assignment operator. */
|
||||
RefMap<K, V> &operator=(const RefMap<K, V> &other) {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
_data = other._data;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Move assignment operator. */
|
||||
RefMap<K, V> &operator=(RefMap<K, V> &&other) noexcept {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
_data = std::move(other._data);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Retains all the objects in the map */
|
||||
void addRefForAllObjects() {
|
||||
for (const auto &element : _data) {
|
||||
element.second->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::unordered_map<K, V> _data;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
523
cocos/base/RefVector.h
Normal file
523
cocos/base/RefVector.h
Normal file
@@ -0,0 +1,523 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <algorithm> // for std::find
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "base/Random.h"
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
/*
|
||||
* Similar to ccstd::vector, but it will manage reference count automatically internally.
|
||||
* Which means it will invoke RefCounted::addRef() when adding an element, and invoke RefCounted::release() when removing an element.
|
||||
* @warn The element should be `RefCounted` or its sub-class.
|
||||
*/
|
||||
template <class T>
|
||||
class RefVector {
|
||||
public:
|
||||
// ------------------------------------------
|
||||
// Iterators
|
||||
// ------------------------------------------
|
||||
|
||||
/** Iterator, can be used to loop the Vector. */
|
||||
using iterator = typename ccstd::vector<T>::iterator;
|
||||
/** Const iterator, can be used to loop the Vector. */
|
||||
using const_iterator = typename ccstd::vector<T>::const_iterator;
|
||||
|
||||
/** Reversed iterator, can be used to loop the Vector in reverse sequence. */
|
||||
using reverse_iterator = typename ccstd::vector<T>::reverse_iterator;
|
||||
/** Reversed iterator, can be used to loop the Vector in reverse sequence. */
|
||||
using const_reverse_iterator = typename ccstd::vector<T>::const_reverse_iterator;
|
||||
|
||||
/** Returns an iterator pointing the first element of the Vector. */
|
||||
iterator begin() { return _data.begin(); }
|
||||
/** Returns an iterator pointing the first element of the Vector. */
|
||||
const_iterator begin() const { return _data.begin(); }
|
||||
|
||||
/**
|
||||
* Returns an iterator referring to the `past-the-end` element in the Vector container.
|
||||
* The past-the-end element is the theoretical element that would follow the last element in the Vector.
|
||||
* It does not point to any element, and thus shall not be dereferenced.
|
||||
*/
|
||||
iterator end() { return _data.end(); }
|
||||
/**
|
||||
* Returns iterator referring to the `past-the-end` element in the Vector container.
|
||||
* The past-the-end element is the theoretical element that would follow the last element in the Vector.
|
||||
* It does not point to any element, and thus shall not be dereferenced.
|
||||
*/
|
||||
const_iterator end() const { return _data.end(); }
|
||||
|
||||
/** Returns a const_iterator pointing the first element of the Vector. */
|
||||
const_iterator cbegin() const { return _data.cbegin(); }
|
||||
/** Returns a const_iterator pointing the `past-the-end` element of the Vector. */
|
||||
const_iterator cend() const { return _data.cend(); }
|
||||
|
||||
/** Returns a reverse iterator pointing to the last element of the Vector. */
|
||||
reverse_iterator rbegin() { return _data.rbegin(); }
|
||||
/** Returns a reverse iterator pointing to the last element of the Vector. */
|
||||
const_reverse_iterator rbegin() const { return _data.rbegin(); }
|
||||
|
||||
/** Returns a reverse iterator pointing to the theoretical element preceding the
|
||||
* first element of the vector (which is considered its reverse end).
|
||||
*/
|
||||
reverse_iterator rend() { return _data.rend(); }
|
||||
/** Returns a reverse iterator pointing to the theoretical element preceding the
|
||||
* first element of the vector (which is considered its reverse end).
|
||||
*/
|
||||
const_reverse_iterator rend() const { return _data.rend(); }
|
||||
|
||||
/** Returns a const_reverse_iterator pointing to the last element in the container (i.e., its reverse beginning). */
|
||||
const_reverse_iterator crbegin() const { return _data.crbegin(); }
|
||||
/** Returns a const_reverse_iterator pointing to the theoretical element preceding the first element in
|
||||
* the container (which is considered its reverse end).
|
||||
*/
|
||||
const_reverse_iterator crend() const { return _data.crend(); }
|
||||
|
||||
/** Constructor. */
|
||||
RefVector<T>()
|
||||
: _data() {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a capacity.
|
||||
* @param capacity Capacity of the Vector.
|
||||
*/
|
||||
explicit RefVector<T>(uint32_t capacity)
|
||||
: _data() {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
// CC_LOG_INFO("In the default constructor with capacity of Vector.");
|
||||
reserve(capacity);
|
||||
}
|
||||
|
||||
/** Constructor with initializer list. */
|
||||
RefVector<T>(std::initializer_list<T> list) {
|
||||
for (auto &element : list) {
|
||||
pushBack(element);
|
||||
}
|
||||
}
|
||||
|
||||
/** Destructor. */
|
||||
~RefVector<T>() {
|
||||
// CC_LOG_INFO("In the destructor of Vector.");
|
||||
clear();
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
RefVector<T>(const RefVector<T> &other) {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
// CC_LOG_INFO("In the copy constructor!");
|
||||
_data = other._data;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
explicit RefVector<T>(const ccstd::vector<T> &other) {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
// CC_LOG_INFO("In the copy constructor!");
|
||||
_data = other;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
|
||||
/** Constructor with std::move semantic. */
|
||||
RefVector<T>(RefVector<T> &&other) noexcept {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
// CC_LOG_INFO("In the move constructor of Vector!");
|
||||
_data = std::move(other._data);
|
||||
}
|
||||
|
||||
/** Constructor with std::move semantic. */
|
||||
explicit RefVector<T>(ccstd::vector<T> &&other) noexcept {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
// CC_LOG_INFO("In the move constructor of Vector!");
|
||||
_data = std::move(other);
|
||||
// NOTE: The reference count of T in ccstd::vector may be 0 so we need to retain all elements in ccstd::vector.
|
||||
addRefForAllObjects();
|
||||
}
|
||||
|
||||
/** Copy assignment operator. */
|
||||
RefVector<T> &operator=(const RefVector<T> &other) {
|
||||
if (this != &other) {
|
||||
// CC_LOG_INFO("In the copy assignment operator!");
|
||||
clear();
|
||||
_data = other._data;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefVector<T> &operator=(const ccstd::vector<T> &other) {
|
||||
static_assert(std::is_convertible<T, RefCounted *>::value, "Invalid Type for cc::Vector<T>!");
|
||||
if (&_data != &other) {
|
||||
// CC_LOG_INFO("In the copy assign operator!");
|
||||
clear();
|
||||
_data = other;
|
||||
addRefForAllObjects();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Move assignment operator with std::move semantic. */
|
||||
RefVector<T> &operator=(RefVector<T> &&other) noexcept {
|
||||
if (this != &other) {
|
||||
// CC_LOG_INFO("In the move assignment operator!");
|
||||
clear();
|
||||
_data = std::move(other._data);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefVector<T> &operator=(ccstd::vector<T> &&other) noexcept {
|
||||
if (&_data != &other) {
|
||||
// CC_LOG_INFO("In the move assignment operator!");
|
||||
clear();
|
||||
_data = std::move(other);
|
||||
// NOTE: The reference count of T in ccstd::vector may be 0 so we need to retain all elements in ccstd::vector.
|
||||
addRefForAllObjects();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RefVector<T> &operator=(std::initializer_list<T> list) {
|
||||
clear();
|
||||
for (auto &element : list) {
|
||||
pushBack(element);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Can not return reference, or it can use like this
|
||||
// refVector[i] = val;
|
||||
// Then, reference count will be wrong. In order to correct reference count, should:
|
||||
// - dec refVector[i] reference count
|
||||
// - add `val` reference count.
|
||||
// It is hard to use, so delete it.
|
||||
T &operator[](uint32_t idx) = delete;
|
||||
// As non const version is disabled, disable const version too.
|
||||
const T &operator[](uint32_t idx) const = delete;
|
||||
|
||||
/**
|
||||
* Requests that the vector capacity be at least enough to contain n elements.
|
||||
* @param capacity Minimum capacity requested of the Vector.
|
||||
*/
|
||||
void reserve(uint32_t n) {
|
||||
_data.reserve(n);
|
||||
}
|
||||
|
||||
/** @brief Returns the size of the storage space currently allocated for the Vector, expressed in terms of elements.
|
||||
* @note This capacity is not necessarily equal to the Vector size.
|
||||
* It can be equal or greater, with the extra space allowing to accommodate for growth without the need to reallocate on each insertion.
|
||||
* @return The size of the currently allocated storage capacity in the Vector, measured in terms of the number elements it can hold.
|
||||
*/
|
||||
uint32_t capacity() const {
|
||||
return _data.capacity();
|
||||
}
|
||||
|
||||
/** @brief Returns the number of elements in the Vector.
|
||||
* @note This is the number of actual objects held in the Vector, which is not necessarily equal to its storage capacity.
|
||||
* @return The number of elements in the Vector.
|
||||
*/
|
||||
uint32_t size() const {
|
||||
return static_cast<uint32_t>(_data.size());
|
||||
}
|
||||
|
||||
/** @brief Returns whether the Vector is empty (i.e. whether its size is 0).
|
||||
* @note This function does not modify the container in any way. To clear the content of a vector, see Vector<T>::clear.
|
||||
*/
|
||||
bool empty() const {
|
||||
return _data.empty();
|
||||
}
|
||||
|
||||
/** Returns the maximum number of elements that the Vector can hold. */
|
||||
uint32_t maxSize() const {
|
||||
return _data.max_size();
|
||||
}
|
||||
|
||||
/** Returns index of a certain object, return UINT_MAX if doesn't contain the object */
|
||||
uint32_t getIndex(T object) const {
|
||||
auto iter = std::find(_data.begin(), _data.end(), object);
|
||||
if (iter != _data.end()) {
|
||||
return iter - _data.begin();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** @brief Find the object in the Vector.
|
||||
* @param object The object to find.
|
||||
* @return Returns an iterator which refers to the element that its value is equals to object.
|
||||
* Returns Vector::end() if not found.
|
||||
*/
|
||||
const_iterator find(T object) const {
|
||||
return std::find(_data.begin(), _data.end(), object);
|
||||
}
|
||||
|
||||
/** @brief Find the object in the Vector.
|
||||
* @param object The object to find.
|
||||
* @return Returns an iterator which refers to the element that its value is equals to object.
|
||||
* Returns Vector::end() if not found.
|
||||
*/
|
||||
iterator find(T object) {
|
||||
return std::find(_data.begin(), _data.end(), object);
|
||||
}
|
||||
|
||||
/** Returns the element at position 'index' in the Vector. */
|
||||
const T &at(uint32_t index) const {
|
||||
CC_ASSERT(index < size());
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
T &at(uint32_t index) {
|
||||
CC_ASSERT(index < size());
|
||||
return _data[index];
|
||||
}
|
||||
|
||||
/** Returns the first element in the Vector. */
|
||||
T front() const {
|
||||
return _data.front();
|
||||
}
|
||||
|
||||
/** Returns the last element of the Vector. */
|
||||
T back() const {
|
||||
return _data.back();
|
||||
}
|
||||
|
||||
/** Returns a random element of the Vector. */
|
||||
T getRandomObject() const {
|
||||
if (!_data.empty()) {
|
||||
auto randIdx = RandomHelper::randomInt<int>(0, static_cast<int>(_data.size()) - 1);
|
||||
return *(_data.begin() + randIdx);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether an object is in the container.
|
||||
* @param object The object to be checked.
|
||||
* @return True if the object is in the container, false if not.
|
||||
*/
|
||||
bool contains(T object) const {
|
||||
return (std::find(_data.begin(), _data.end(), object) != _data.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether two vectors are equal.
|
||||
* @param other The vector to be compared.
|
||||
* @return True if two vectors are equal, false if not.
|
||||
*/
|
||||
bool equals(const RefVector<T> &other) const {
|
||||
uint32_t s = this->size();
|
||||
if (s != other.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < s; i++) {
|
||||
if (this->at(i) != other.at(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adds objects
|
||||
|
||||
/** Adds a new element at the end of the Vector. */
|
||||
void pushBack(T object) {
|
||||
CC_ASSERT_NOT_NULL(object);
|
||||
_data.push_back(object);
|
||||
object->addRef();
|
||||
}
|
||||
|
||||
/** Push all elements of an existing Vector to the end of current Vector. */
|
||||
void pushBack(const RefVector<T> &other) {
|
||||
for (const auto &obj : other) {
|
||||
_data.push_back(obj);
|
||||
obj->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert an object at certain index.
|
||||
* @param index The index to be inserted at.
|
||||
* @param object The object to be inserted.
|
||||
*/
|
||||
void insert(uint32_t index, T object) {
|
||||
CC_ASSERT(index <= size());
|
||||
CC_ASSERT_NOT_NULL(object);
|
||||
_data.insert((std::begin(_data) + index), object);
|
||||
object->addRef();
|
||||
}
|
||||
|
||||
// Removes Objects
|
||||
|
||||
/** Removes the last element in the Vector. */
|
||||
void popBack() {
|
||||
CC_ASSERT(!_data.empty());
|
||||
auto last = _data.back();
|
||||
_data.pop_back();
|
||||
last->release();
|
||||
}
|
||||
|
||||
/** Remove a certain object in Vector.
|
||||
* @param object The object to be removed.
|
||||
* @param removeAll Whether to remove all elements with the same value.
|
||||
* If its value is 'false', it will just erase the first occurrence.
|
||||
*/
|
||||
void eraseObject(T object, bool removeAll = false) {
|
||||
CC_ASSERT_NOT_NULL(object);
|
||||
|
||||
if (removeAll) {
|
||||
for (auto iter = _data.begin(); iter != _data.end();) {
|
||||
if ((*iter) == object) {
|
||||
iter = _data.erase(iter);
|
||||
object->release();
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto iter = std::find(_data.begin(), _data.end(), object);
|
||||
if (iter != _data.end()) {
|
||||
_data.erase(iter);
|
||||
object->release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Removes from the vector with an iterator.
|
||||
* @param position Iterator pointing to a single element to be removed from the Vector.
|
||||
* @return An iterator pointing to the new location of the element that followed the last element erased by the function call.
|
||||
* This is the container end if the operation erased the last element in the sequence.
|
||||
*/
|
||||
iterator erase(iterator position) {
|
||||
CC_ASSERT(position >= _data.begin() && position < _data.end());
|
||||
(*position)->release();
|
||||
return _data.erase(position);
|
||||
}
|
||||
|
||||
/** @brief Removes from the Vector with a range of elements ( [first, last) ).
|
||||
* @param first The beginning of the range.
|
||||
* @param last The end of the range, the 'last' will not be removed, it's only for indicating the end of range.
|
||||
* @return An iterator pointing to the new location of the element that followed the last element erased by the function call.
|
||||
* This is the container end if the operation erased the last element in the sequence.
|
||||
*/
|
||||
iterator erase(iterator first, iterator last) {
|
||||
for (auto iter = first; iter != last; ++iter) {
|
||||
(*iter)->release();
|
||||
}
|
||||
|
||||
return _data.erase(first, last);
|
||||
}
|
||||
|
||||
/** @brief Removes from the Vector by index.
|
||||
* @param index The index of the element to be removed from the Vector.
|
||||
* @return An iterator pointing to the successor of Vector[index].
|
||||
*/
|
||||
iterator erase(uint32_t index) {
|
||||
CC_ASSERT(!_data.empty() && index < size());
|
||||
auto it = std::next(begin(), index);
|
||||
(*it)->release();
|
||||
return _data.erase(it);
|
||||
}
|
||||
|
||||
/** @brief Removes all elements from the Vector (which are destroyed), leaving the container with a size of 0.
|
||||
* @note All the elements in the Vector will be released (reference count will be decreased).
|
||||
*/
|
||||
void clear() {
|
||||
for (auto it = std::begin(_data); it != std::end(_data); ++it) {
|
||||
auto *ptr = *it;
|
||||
if (ptr) {
|
||||
ptr->release();
|
||||
}
|
||||
}
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
// Rearranging Content
|
||||
|
||||
/** Swap the values object1 and object2. */
|
||||
void swap(T object1, T object2) {
|
||||
uint32_t idx1 = getIndex(object1);
|
||||
uint32_t idx2 = getIndex(object2);
|
||||
std::swap(_data[idx1], _data[idx2]);
|
||||
}
|
||||
|
||||
/** Swap two elements by indexes. */
|
||||
void swap(uint32_t index1, uint32_t index2) {
|
||||
CC_ASSERT(index1 < size() && index2 < size());
|
||||
std::swap(_data[index1], _data[index2]);
|
||||
}
|
||||
|
||||
/** Replace value at index with given object. */
|
||||
void replace(uint32_t index, T object) {
|
||||
CC_ASSERT(index < size());
|
||||
CC_ASSERT_NOT_NULL(object);
|
||||
|
||||
CC_SAFE_RELEASE(_data[index]);
|
||||
_data[index] = object;
|
||||
CC_SAFE_ADD_REF(object);
|
||||
}
|
||||
|
||||
/** Reverses the Vector. */
|
||||
void reverse() {
|
||||
std::reverse(std::begin(_data), std::end(_data));
|
||||
}
|
||||
|
||||
/** Requests the container to reduce its capacity to fit its size. */
|
||||
void shrinkToFit() {
|
||||
_data.shrink_to_fit();
|
||||
}
|
||||
|
||||
const ccstd::vector<T> &get() const {
|
||||
return _data;
|
||||
}
|
||||
|
||||
void resize(uint32_t size) {
|
||||
_data.resize(size);
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Retains all the objects in the vector */
|
||||
void addRefForAllObjects() {
|
||||
for (const auto &obj : _data) {
|
||||
obj->addRef();
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::vector<T> _data;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
398
cocos/base/Scheduler.cpp
Normal file
398
cocos/base/Scheduler.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Scheduler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include "base/Log.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/memory/Memory.h"
|
||||
|
||||
namespace {
|
||||
constexpr unsigned CC_REPEAT_FOREVER{UINT_MAX - 1};
|
||||
constexpr int MAX_FUNC_TO_PERFORM{30};
|
||||
constexpr int INITIAL_TIMER_COUND{10};
|
||||
} // namespace
|
||||
|
||||
namespace cc {
|
||||
// implementation Timer
|
||||
|
||||
void Timer::setupTimerWithInterval(float seconds, unsigned int repeat, float delay) {
|
||||
_elapsed = -1;
|
||||
_interval = seconds;
|
||||
_delay = delay;
|
||||
_useDelay = _delay > 0.0F;
|
||||
_repeat = repeat;
|
||||
_runForever = _repeat == CC_REPEAT_FOREVER;
|
||||
}
|
||||
|
||||
void Timer::update(float dt) {
|
||||
if (_elapsed == -1) {
|
||||
_elapsed = 0;
|
||||
_timesExecuted = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// accumulate elapsed time
|
||||
_elapsed += dt;
|
||||
|
||||
// deal with delay
|
||||
if (_useDelay) {
|
||||
if (_elapsed < _delay) {
|
||||
return;
|
||||
}
|
||||
trigger(_delay);
|
||||
_elapsed = _elapsed - _delay;
|
||||
_timesExecuted += 1;
|
||||
_useDelay = false;
|
||||
// after delay, the rest time should compare with interval
|
||||
if (!_runForever && _timesExecuted > _repeat) { //unschedule timer
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if _interval == 0, should trigger once every frame
|
||||
float interval = (_interval > 0) ? _interval : _elapsed;
|
||||
while (_elapsed >= interval) {
|
||||
trigger(interval);
|
||||
_elapsed -= interval;
|
||||
_timesExecuted += 1;
|
||||
|
||||
if (!_runForever && _timesExecuted > _repeat) {
|
||||
cancel();
|
||||
break;
|
||||
}
|
||||
|
||||
if (_elapsed <= 0.F) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (_scheduler->isCurrentTargetSalvaged()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TimerTargetCallback
|
||||
|
||||
bool TimerTargetCallback::initWithCallback(Scheduler *scheduler, const ccSchedulerFunc &callback, void *target, const ccstd::string &key, float seconds, unsigned int repeat, float delay) {
|
||||
_scheduler = scheduler;
|
||||
_target = target;
|
||||
_callback = callback;
|
||||
_key = key;
|
||||
setupTimerWithInterval(seconds, repeat, delay);
|
||||
return true;
|
||||
}
|
||||
|
||||
void TimerTargetCallback::trigger(float dt) {
|
||||
if (_callback) {
|
||||
_callback(dt);
|
||||
}
|
||||
}
|
||||
|
||||
void TimerTargetCallback::cancel() {
|
||||
_scheduler->unschedule(_key, _target);
|
||||
}
|
||||
|
||||
// implementation of Scheduler
|
||||
|
||||
Scheduler::Scheduler() {
|
||||
// I don't expect to have more than 30 functions to all per frame
|
||||
_functionsToPerform.reserve(MAX_FUNC_TO_PERFORM);
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler() {
|
||||
unscheduleAll();
|
||||
}
|
||||
|
||||
void Scheduler::removeHashElement(HashTimerEntry *element) {
|
||||
if (element) {
|
||||
for (auto &timer : element->timers) {
|
||||
timer->release();
|
||||
}
|
||||
element->timers.clear();
|
||||
|
||||
_hashForTimers.erase(element->target);
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::schedule(const ccSchedulerFunc &callback, void *target, float interval, bool paused, const ccstd::string &key) {
|
||||
this->schedule(callback, target, interval, CC_REPEAT_FOREVER, 0.0F, paused, key);
|
||||
}
|
||||
|
||||
void Scheduler::schedule(const ccSchedulerFunc &callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const ccstd::string &key) {
|
||||
CC_ASSERT(target);
|
||||
CC_ASSERT(!key.empty());
|
||||
|
||||
auto iter = _hashForTimers.find(target);
|
||||
HashTimerEntry *element = nullptr;
|
||||
if (iter == _hashForTimers.end()) {
|
||||
element = ccnew HashTimerEntry();
|
||||
element->target = target;
|
||||
|
||||
_hashForTimers[target] = element;
|
||||
|
||||
// Is this the 1st element ? Then set the pause level to all the selectors of this target
|
||||
element->paused = paused;
|
||||
} else {
|
||||
element = iter->second;
|
||||
CC_ASSERT(element->paused == paused);
|
||||
}
|
||||
|
||||
if (element->timers.empty()) {
|
||||
element->timers.reserve(INITIAL_TIMER_COUND);
|
||||
} else {
|
||||
for (auto &e : element->timers) {
|
||||
auto *timer = dynamic_cast<TimerTargetCallback *>(e);
|
||||
if (key == timer->getKey()) {
|
||||
CC_LOG_DEBUG("CCScheduler#scheduleSelector. Selector already scheduled. Updating interval from: %.4f to %.4f", timer->getInterval(), interval);
|
||||
timer->setInterval(interval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto *timer = ccnew TimerTargetCallback();
|
||||
timer->addRef();
|
||||
timer->initWithCallback(this, callback, target, key, interval, repeat, delay);
|
||||
element->timers.emplace_back(timer);
|
||||
}
|
||||
|
||||
void Scheduler::unschedule(const ccstd::string &key, void *target) {
|
||||
// explicit handle nil arguments when removing an object
|
||||
if (target == nullptr || key.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
HashTimerEntry *element = iter->second;
|
||||
int i = 0;
|
||||
auto &timers = element->timers;
|
||||
|
||||
for (auto *t : timers) {
|
||||
auto *timer = dynamic_cast<TimerTargetCallback *>(t);
|
||||
|
||||
if (timer && key == timer->getKey()) {
|
||||
if (timer == element->currentTimer && (!element->currentTimerSalvaged)) {
|
||||
element->currentTimer->addRef();
|
||||
element->currentTimerSalvaged = true;
|
||||
}
|
||||
|
||||
timers.erase(timers.begin() + i);
|
||||
timer->release();
|
||||
|
||||
// update timerIndex in case we are in tick:, looping over the actions
|
||||
if (element->timerIndex >= i) {
|
||||
element->timerIndex--;
|
||||
}
|
||||
|
||||
if (timers.empty()) {
|
||||
if (_currentTarget == element) {
|
||||
_currentTargetSalvaged = true;
|
||||
} else {
|
||||
removeHashElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Scheduler::isScheduled(const ccstd::string &key, void *target) {
|
||||
CC_ASSERT(!key.empty());
|
||||
CC_ASSERT(target);
|
||||
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter == _hashForTimers.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HashTimerEntry *element = iter->second;
|
||||
if (element->timers.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &timers = element->timers;
|
||||
return std::any_of(timers.begin(), timers.end(), [&key](Timer *t) {
|
||||
auto *timer = dynamic_cast<TimerTargetCallback *>(t);
|
||||
return (timer && key == timer->getKey());
|
||||
});
|
||||
}
|
||||
|
||||
void Scheduler::unscheduleAll() {
|
||||
for (auto iter = _hashForTimers.begin(); iter != _hashForTimers.end();) {
|
||||
unscheduleAllForTarget(iter++->first);
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::unscheduleAllForTarget(void *target) {
|
||||
// explicit nullptr handling
|
||||
if (target == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Custom Selectors
|
||||
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
HashTimerEntry *element = iter->second;
|
||||
auto &timers = element->timers;
|
||||
if (std::find(timers.begin(), timers.end(), element->currentTimer) != timers.end() &&
|
||||
(!element->currentTimerSalvaged)) {
|
||||
element->currentTimer->addRef();
|
||||
element->currentTimerSalvaged = true;
|
||||
}
|
||||
|
||||
for (auto *t : timers) {
|
||||
t->release();
|
||||
}
|
||||
timers.clear();
|
||||
|
||||
if (_currentTarget == element) {
|
||||
_currentTargetSalvaged = true;
|
||||
} else {
|
||||
removeHashElement(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::resumeTarget(void *target) {
|
||||
CC_ASSERT_NOT_NULL(target);
|
||||
|
||||
// custom selectors
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
iter->second->paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Scheduler::pauseTarget(void *target) {
|
||||
CC_ASSERT_NOT_NULL(target);
|
||||
|
||||
// custom selectors
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
iter->second->paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Scheduler::isTargetPaused(void *target) {
|
||||
CC_ASSERT_NOT_NULL(target);
|
||||
|
||||
// Custom selectors
|
||||
auto iter = _hashForTimers.find(target);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
return iter->second->paused;
|
||||
}
|
||||
|
||||
return false; // should never get here
|
||||
}
|
||||
|
||||
void Scheduler::performFunctionInCocosThread(const std::function<void()> &function) {
|
||||
_performMutex.lock();
|
||||
_functionsToPerform.push_back(function);
|
||||
_performMutex.unlock();
|
||||
}
|
||||
|
||||
void Scheduler::removeAllFunctionsToBePerformedInCocosThread() {
|
||||
std::unique_lock<std::mutex> lock(_performMutex);
|
||||
_functionsToPerform.clear();
|
||||
}
|
||||
|
||||
// main loop
|
||||
void Scheduler::update(float dt) {
|
||||
_updateHashLocked = true;
|
||||
|
||||
// Iterate over all the custom selectors
|
||||
HashTimerEntry *elt = nullptr;
|
||||
for (auto iter = _hashForTimers.begin(); iter != _hashForTimers.end();) {
|
||||
elt = iter->second;
|
||||
_currentTarget = elt;
|
||||
_currentTargetSalvaged = false;
|
||||
|
||||
if (!_currentTarget->paused) {
|
||||
// The 'timers' array may change while inside this loop
|
||||
for (elt->timerIndex = 0; elt->timerIndex < static_cast<int>(elt->timers.size()); ++(elt->timerIndex)) {
|
||||
elt->currentTimer = elt->timers.at(elt->timerIndex);
|
||||
elt->currentTimerSalvaged = false;
|
||||
|
||||
elt->currentTimer->update(dt);
|
||||
|
||||
if (elt->currentTimerSalvaged) {
|
||||
// The currentTimer told the remove itself. To prevent the timer from
|
||||
// accidentally deallocating itself before finishing its step, we retained
|
||||
// it. Now that step is done, it's safe to release it.
|
||||
elt->currentTimer->release();
|
||||
}
|
||||
|
||||
elt->currentTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// only delete currentTarget if no actions were scheduled during the cycle (issue #481)
|
||||
if (_currentTargetSalvaged && _currentTarget->timers.empty()) {
|
||||
++iter;
|
||||
removeHashElement(_currentTarget);
|
||||
if (iter != _hashForTimers.end()) {
|
||||
++iter;
|
||||
}
|
||||
} else {
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
_updateHashLocked = false;
|
||||
_currentTarget = nullptr;
|
||||
|
||||
//
|
||||
// Functions allocated from another thread
|
||||
//
|
||||
|
||||
// Testing size is faster than locking / unlocking.
|
||||
// And almost never there will be functions scheduled to be called.
|
||||
if (!_functionsToPerform.empty()) {
|
||||
_performMutex.lock();
|
||||
// fixed #4123: Save the callback functions, they must be invoked after '_performMutex.unlock()', otherwise if new functions are added in callback, it will cause thread deadlock.
|
||||
auto temp = _functionsToPerform;
|
||||
_functionsToPerform.clear();
|
||||
_performMutex.unlock();
|
||||
for (const auto &function : temp) {
|
||||
function();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
305
cocos/base/Scheduler.h
Normal file
305
cocos/base/Scheduler.h
Normal file
@@ -0,0 +1,305 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2008-2010 Ricardo Quesada
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2011 Zynga Inc.
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
#include "base/RefCounted.h"
|
||||
#include "base/std/container/set.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Scheduler;
|
||||
|
||||
using ccSchedulerFunc = std::function<void(float)>;
|
||||
|
||||
/**
|
||||
* @cond
|
||||
*/
|
||||
class CC_DLL Timer : public RefCounted {
|
||||
public:
|
||||
/** get interval in seconds */
|
||||
inline float getInterval() const { return _interval; };
|
||||
/** set interval in seconds */
|
||||
inline void setInterval(float interval) { _interval = interval; };
|
||||
|
||||
void setupTimerWithInterval(float seconds, unsigned int repeat, float delay);
|
||||
|
||||
virtual void trigger(float dt) = 0;
|
||||
virtual void cancel() = 0;
|
||||
|
||||
/** triggers the timer */
|
||||
void update(float dt);
|
||||
|
||||
protected:
|
||||
Timer() = default;
|
||||
|
||||
Scheduler *_scheduler = nullptr;
|
||||
float _elapsed = 0.F;
|
||||
bool _runForever = false;
|
||||
bool _useDelay = false;
|
||||
unsigned int _timesExecuted = 0;
|
||||
unsigned int _repeat = 0; //0 = once, 1 is 2 x executed
|
||||
float _delay = 0.F;
|
||||
float _interval = 0.F;
|
||||
};
|
||||
|
||||
class CC_DLL TimerTargetCallback final : public Timer {
|
||||
public:
|
||||
TimerTargetCallback() = default;
|
||||
|
||||
// Initializes a timer with a target, a lambda and an interval in seconds, repeat in number of times to repeat, delay in seconds.
|
||||
bool initWithCallback(Scheduler *scheduler, const ccSchedulerFunc &callback, void *target, const ccstd::string &key, float seconds, unsigned int repeat, float delay);
|
||||
|
||||
inline const ccSchedulerFunc &getCallback() const { return _callback; };
|
||||
inline const ccstd::string &getKey() const { return _key; };
|
||||
|
||||
void trigger(float dt) override;
|
||||
void cancel() override;
|
||||
|
||||
private:
|
||||
void *_target = nullptr;
|
||||
ccSchedulerFunc _callback = nullptr;
|
||||
ccstd::string _key;
|
||||
};
|
||||
|
||||
/**
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup base
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct _listEntry;
|
||||
struct _hashSelectorEntry;
|
||||
struct _hashUpdateEntry;
|
||||
|
||||
/** @brief Scheduler is responsible for triggering the scheduled callbacks.
|
||||
You should not use system timer for your game logic. Instead, use this class.
|
||||
|
||||
There are 2 different types of callbacks (selectors):
|
||||
|
||||
- update selector: the 'update' selector will be called every frame. You can customize the priority.
|
||||
- custom selector: A custom selector will be called every frame, or with a custom interval of time
|
||||
|
||||
The 'custom selectors' should be avoided when possible. It is faster, and consumes less memory to use the 'update selector'.
|
||||
|
||||
*/
|
||||
class CC_DLL Scheduler final {
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @js ctor
|
||||
*/
|
||||
Scheduler();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*
|
||||
* @js NA
|
||||
* @lua NA
|
||||
*/
|
||||
~Scheduler();
|
||||
|
||||
/** 'update' the scheduler.
|
||||
* You should NEVER call this method, unless you know what you are doing.
|
||||
* @lua NA
|
||||
*/
|
||||
void update(float dt);
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
// schedule
|
||||
|
||||
/** The scheduled method will be called every 'interval' seconds.
|
||||
If paused is true, then it won't be called until it is resumed.
|
||||
If 'interval' is 0, it will be called every frame, but if so, it's recommended to use 'scheduleUpdate' instead.
|
||||
If the 'callback' is already scheduled, then only the interval parameter will be updated without re-scheduling it again.
|
||||
repeat let the action be repeated repeat + 1 times, use CC_REPEAT_FOREVER to let the action run continuously
|
||||
delay is the amount of time the action will wait before it'll start.
|
||||
@param callback The callback function.
|
||||
@param target The target of the callback function.
|
||||
@param interval The interval to schedule the callback. If the value is 0, then the callback will be scheduled every frame.
|
||||
@param repeat repeat+1 times to schedule the callback.
|
||||
@param delay Schedule call back after `delay` seconds. If the value is not 0, the first schedule will happen after `delay` seconds.
|
||||
But it will only affect first schedule. After first schedule, the delay time is determined by `interval`.
|
||||
@param paused Whether or not to pause the schedule.
|
||||
@param key The key to identify the callback function, because there is not way to identify a std::function<>.
|
||||
@since v3.0
|
||||
*/
|
||||
void schedule(const ccSchedulerFunc &callback, void *target, float interval, unsigned int repeat, float delay, bool paused, const ccstd::string &key);
|
||||
|
||||
/** The scheduled method will be called every 'interval' seconds for ever.
|
||||
@param callback The callback function.
|
||||
@param target The target of the callback function.
|
||||
@param interval The interval to schedule the callback. If the value is 0, then the callback will be scheduled every frame.
|
||||
@param paused Whether or not to pause the schedule.
|
||||
@param key The key to identify the callback function, because there is not way to identify a std::function<>.
|
||||
@since v3.0
|
||||
*/
|
||||
void schedule(const ccSchedulerFunc &callback, void *target, float interval, bool paused, const ccstd::string &key);
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
// unschedule
|
||||
|
||||
/** Unschedules a callback for a key and a given target.
|
||||
If you want to unschedule the 'callbackPerFrame', use unscheduleUpdate.
|
||||
@param key The key to identify the callback function, because there is not way to identify a std::function<>.
|
||||
@param target The target to be unscheduled.
|
||||
@since v3.0
|
||||
*/
|
||||
void unschedule(const ccstd::string &key, void *target);
|
||||
|
||||
/** Unschedules all selectors for a given target.
|
||||
This also includes the "update" selector.
|
||||
@param target The target to be unscheduled.
|
||||
@since v0.99.3
|
||||
@lua NA
|
||||
*/
|
||||
void unscheduleAllForTarget(void *target);
|
||||
|
||||
/** Unschedules all selectors from all targets.
|
||||
You should NEVER call this method, unless you know what you are doing.
|
||||
@since v0.99.3
|
||||
*/
|
||||
void unscheduleAll();
|
||||
|
||||
/** Unschedules all selectors from all targets with a minimum priority.
|
||||
You should only call this with `PRIORITY_NON_SYSTEM_MIN` or higher.
|
||||
@param minPriority The minimum priority of selector to be unscheduled. Which means, all selectors which
|
||||
priority is higher than minPriority will be unscheduled.
|
||||
@since v2.0.0
|
||||
*/
|
||||
void unscheduleAllWithMinPriority(int minPriority);
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
// isScheduled
|
||||
|
||||
/** Checks whether a callback associated with 'key' and 'target' is scheduled.
|
||||
@param key The key to identify the callback function, because there is not way to identify a std::function<>.
|
||||
@param target The target of the callback.
|
||||
@return True if the specified callback is invoked, false if not.
|
||||
@since v3.0.0
|
||||
*/
|
||||
bool isScheduled(const ccstd::string &key, void *target);
|
||||
|
||||
/////////////////////////////////////
|
||||
|
||||
/** Pauses the target.
|
||||
All scheduled selectors/update for a given target won't be 'ticked' until the target is resumed.
|
||||
If the target is not present, nothing happens.
|
||||
@param target The target to be paused.
|
||||
@since v0.99.3
|
||||
*/
|
||||
void pauseTarget(void *target);
|
||||
|
||||
/** Resumes the target.
|
||||
The 'target' will be unpaused, so all schedule selectors/update will be 'ticked' again.
|
||||
If the target is not present, nothing happens.
|
||||
@param target The target to be resumed.
|
||||
@since v0.99.3
|
||||
*/
|
||||
void resumeTarget(void *target);
|
||||
|
||||
/** Returns whether or not the target is paused.
|
||||
* @param target The target to be checked.
|
||||
* @return True if the target is paused, false if not.
|
||||
* @since v1.0.0
|
||||
* @lua NA
|
||||
*/
|
||||
bool isTargetPaused(void *target);
|
||||
|
||||
/** Pause all selectors from all targets with a minimum priority.
|
||||
You should only call this with PRIORITY_NON_SYSTEM_MIN or higher.
|
||||
@param minPriority The minimum priority of selector to be paused. Which means, all selectors which
|
||||
priority is higher than minPriority will be paused.
|
||||
@since v2.0.0
|
||||
*/
|
||||
ccstd::set<void *> pauseAllTargetsWithMinPriority(int minPriority);
|
||||
|
||||
/** Calls a function on the cocos2d thread. Useful when you need to call a cocos2d function from another thread.
|
||||
This function is thread safe.
|
||||
@param function The function to be run in cocos2d thread.
|
||||
@since v3.0
|
||||
@js NA
|
||||
*/
|
||||
void performFunctionInCocosThread(const std::function<void()> &function);
|
||||
|
||||
/**
|
||||
* Remove all pending functions queued to be performed with Scheduler::performFunctionInCocosThread
|
||||
* Functions unscheduled in this manner will not be executed
|
||||
* This function is thread safe
|
||||
* @since v3.14
|
||||
* @js NA
|
||||
*/
|
||||
void removeAllFunctionsToBePerformedInCocosThread();
|
||||
|
||||
bool isCurrentTargetSalvaged() const { return _currentTargetSalvaged; };
|
||||
|
||||
private:
|
||||
// Hash Element used for "selectors with interval"
|
||||
struct HashTimerEntry {
|
||||
ccstd::vector<Timer *> timers;
|
||||
void *target;
|
||||
int timerIndex;
|
||||
Timer *currentTimer;
|
||||
bool currentTimerSalvaged;
|
||||
bool paused;
|
||||
};
|
||||
|
||||
void removeHashElement(struct HashTimerEntry *element);
|
||||
void removeUpdateFromHash(struct _listEntry *entry);
|
||||
|
||||
// update specific
|
||||
|
||||
// Used for "selectors with interval"
|
||||
ccstd::unordered_map<void *, HashTimerEntry *> _hashForTimers;
|
||||
struct HashTimerEntry *_currentTarget = nullptr;
|
||||
bool _currentTargetSalvaged = false;
|
||||
// If true unschedule will not remove anything from a hash. Elements will only be marked for deletion.
|
||||
bool _updateHashLocked = false;
|
||||
|
||||
// Used for "perform Function"
|
||||
ccstd::vector<std::function<void()>> _functionsToPerform;
|
||||
std::mutex _performMutex;
|
||||
};
|
||||
|
||||
// end of base group
|
||||
/** @} */
|
||||
|
||||
} // namespace cc
|
||||
34
cocos/base/StringHandle.cpp
Normal file
34
cocos/base/StringHandle.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "StringHandle.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
StringHandle::StringHandle(IndexType handle, const char *str) noexcept
|
||||
: IndexHandle(handle),
|
||||
_str(str) {
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
41
cocos/base/StringHandle.h
Normal file
41
cocos/base/StringHandle.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IndexHandle.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class StringHandle final : public IndexHandle<uint32_t> {
|
||||
public:
|
||||
StringHandle() noexcept = default;
|
||||
explicit StringHandle(IndexType handle, const char *str) noexcept;
|
||||
inline char const *str() const noexcept { return _str; }
|
||||
|
||||
private:
|
||||
char const *_str{nullptr};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
144
cocos/base/StringPool.h
Normal file
144
cocos/base/StringPool.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include "StringHandle.h"
|
||||
#include "base/Macros.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
#include "base/std/hash/hash.h"
|
||||
#include "threading/ReadWriteLock.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <bool ThreadSafe>
|
||||
class StringPool final {
|
||||
private:
|
||||
class StringHasher final {
|
||||
public:
|
||||
ccstd::hash_t operator()(const char *str) const noexcept {
|
||||
return ccstd::hash_range(str, str + strlen(str));
|
||||
}
|
||||
};
|
||||
|
||||
class StringEqual final {
|
||||
public:
|
||||
bool operator()(const char *c1, const char *c2) const noexcept {
|
||||
return strcmp(c1, c2) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
StringPool() = default;
|
||||
~StringPool();
|
||||
StringPool(const StringPool &) = delete;
|
||||
StringPool(StringPool &&) = delete;
|
||||
StringPool &operator=(const StringPool &) = delete;
|
||||
StringPool &operator=(StringPool &&) = delete;
|
||||
|
||||
StringHandle stringToHandle(const char *str) noexcept;
|
||||
char const *handleToString(const StringHandle &handle) const noexcept;
|
||||
StringHandle find(const char *str) const noexcept;
|
||||
|
||||
private:
|
||||
StringHandle doStringToHandle(const char *str) noexcept;
|
||||
char const *doHandleToString(const StringHandle &handle) const noexcept;
|
||||
StringHandle doFind(const char *str) const noexcept;
|
||||
|
||||
ccstd::unordered_map<char const *, StringHandle, StringHasher, StringEqual> _stringToHandles{};
|
||||
ccstd::vector<char const *> _handleToStrings{};
|
||||
mutable ReadWriteLock _readWriteLock{};
|
||||
};
|
||||
|
||||
using ThreadSafeStringPool = StringPool<true>;
|
||||
|
||||
template <bool ThreadSafe>
|
||||
StringPool<ThreadSafe>::~StringPool() {
|
||||
for (char const *strCache : _handleToStrings) {
|
||||
delete[] strCache;
|
||||
}
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
inline StringHandle StringPool<ThreadSafe>::stringToHandle(const char *str) noexcept {
|
||||
if (ThreadSafe) {
|
||||
return _readWriteLock.lockWrite([this, str]() {
|
||||
return doStringToHandle(str);
|
||||
});
|
||||
}
|
||||
return doStringToHandle(str);
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
inline char const *StringPool<ThreadSafe>::handleToString(const StringHandle &handle) const noexcept {
|
||||
if (ThreadSafe) {
|
||||
return _readWriteLock.lockRead([this, handle]() {
|
||||
return doHandleToString(handle);
|
||||
});
|
||||
}
|
||||
return doHandleToString(handle);
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
StringHandle StringPool<ThreadSafe>::find(const char *str) const noexcept {
|
||||
if (ThreadSafe) {
|
||||
return _readWriteLock.lockRead([this, str]() {
|
||||
return doFind(str);
|
||||
});
|
||||
}
|
||||
return doFind(str);
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
inline StringHandle StringPool<ThreadSafe>::doStringToHandle(const char *str) noexcept {
|
||||
const auto it = _stringToHandles.find(str);
|
||||
|
||||
if (it == _stringToHandles.end()) {
|
||||
size_t const strLength = strlen(str) + 1;
|
||||
char *const strCache = ccnew char[strLength];
|
||||
strcpy(strCache, str);
|
||||
StringHandle name(static_cast<StringHandle::IndexType>(_handleToStrings.size()), strCache);
|
||||
_handleToStrings.emplace_back(strCache);
|
||||
_stringToHandles.emplace(strCache, name);
|
||||
return name;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
inline const char *StringPool<ThreadSafe>::doHandleToString(const StringHandle &handle) const noexcept {
|
||||
CC_ASSERT(handle < _handleToStrings.size());
|
||||
return _handleToStrings[handle];
|
||||
}
|
||||
|
||||
template <bool ThreadSafe>
|
||||
StringHandle StringPool<ThreadSafe>::doFind(char const *str) const noexcept {
|
||||
auto const it = _stringToHandles.find(str);
|
||||
return it == _stringToHandles.end() ? StringHandle{} : it->second;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
182
cocos/base/StringUtil.cpp
Normal file
182
cocos/base/StringUtil.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "StringUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
#ifndef CC_WGPU_WASM
|
||||
#include "base/ZipUtils.h"
|
||||
#endif
|
||||
#include "base/base64.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "memory/Memory.h"
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
#if defined(_WIN32)
|
||||
int StringUtil::vprintf(char *buf, const char *last, const char *fmt, va_list args) {
|
||||
if (last <= buf) return 0;
|
||||
|
||||
int count = (int)(last - buf);
|
||||
int ret = _vsnprintf_s(buf, count, _TRUNCATE, fmt, args);
|
||||
if (ret < 0) {
|
||||
if (errno == 0) {
|
||||
return count - 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int StringUtil::vprintf(char *buf, const char *last, const char *fmt, va_list args) {
|
||||
if (last <= buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto count = static_cast<int>(last - buf);
|
||||
int ret = vsnprintf(buf, count, fmt, args);
|
||||
if (ret >= count - 1) {
|
||||
return count - 1;
|
||||
}
|
||||
if (ret < 0) {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int StringUtil::printf(char *buf, const char *last, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int ret = vprintf(buf, last, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ccstd::string StringUtil::format(const char *fmt, ...) {
|
||||
char sz[4096];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(sz, sz + sizeof(sz) - 1, fmt, args);
|
||||
va_end(args);
|
||||
return sz;
|
||||
}
|
||||
|
||||
ccstd::vector<ccstd::string> StringUtil::split(const ccstd::string &str, const ccstd::string &delims, uint32_t maxSplits) {
|
||||
ccstd::vector<ccstd::string> strs;
|
||||
if (str.empty()) {
|
||||
return strs;
|
||||
}
|
||||
|
||||
// Pre-allocate some space for performance
|
||||
strs.reserve(maxSplits ? maxSplits + 1 : 16); // 16 is guessed capacity for most case
|
||||
|
||||
uint32_t numSplits{0};
|
||||
|
||||
// Use STL methods
|
||||
size_t start{0};
|
||||
size_t pos{0};
|
||||
do {
|
||||
pos = str.find_first_of(delims, start);
|
||||
if (pos == start) {
|
||||
// Do nothing
|
||||
start = pos + 1;
|
||||
} else if (pos == ccstd::string::npos || (maxSplits && numSplits == maxSplits)) {
|
||||
// Copy the rest of the string
|
||||
strs.push_back(str.substr(start));
|
||||
break;
|
||||
} else {
|
||||
// Copy up to delimiter
|
||||
strs.push_back(str.substr(start, pos - start));
|
||||
start = pos + 1;
|
||||
}
|
||||
// parse up to next real data
|
||||
start = str.find_first_not_of(delims, start);
|
||||
++numSplits;
|
||||
} while (pos != ccstd::string::npos);
|
||||
|
||||
return strs;
|
||||
}
|
||||
|
||||
ccstd::string &StringUtil::replace(ccstd::string &str, const ccstd::string &findStr, const ccstd::string &replaceStr) {
|
||||
size_t startPos = str.find(findStr);
|
||||
if (startPos == ccstd::string::npos) {
|
||||
return str;
|
||||
}
|
||||
str.replace(startPos, findStr.length(), replaceStr);
|
||||
return str;
|
||||
}
|
||||
|
||||
ccstd::string &StringUtil::replaceAll(ccstd::string &str, const ccstd::string &findStr, const ccstd::string &replaceStr) {
|
||||
if (findStr.empty()) {
|
||||
return str;
|
||||
}
|
||||
size_t startPos = 0;
|
||||
while ((startPos = str.find(findStr, startPos)) != ccstd::string::npos) {
|
||||
str.replace(startPos, findStr.length(), replaceStr);
|
||||
startPos += replaceStr.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
ccstd::string &StringUtil::tolower(ccstd::string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
ccstd::string &StringUtil::toupper(ccstd::string &str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c) { return std::toupper(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
ccstd::string GzipedString::value() const { // NOLINT(readability-convert-member-functions-to-static)
|
||||
#ifndef CC_WGPU_WASM
|
||||
uint8_t *outGzip{nullptr};
|
||||
uint8_t *outBase64{nullptr};
|
||||
auto *input = reinterpret_cast<unsigned char *>(const_cast<char *>(_str.c_str()));
|
||||
auto lenOfBase64 = base64Decode(input, static_cast<unsigned int>(_str.size()), &outBase64);
|
||||
auto lenofUnzip = ZipUtils::inflateMemory(outBase64, static_cast<uint32_t>(lenOfBase64), &outGzip);
|
||||
ccstd::string ret(outGzip, outGzip + lenofUnzip);
|
||||
free(outGzip);
|
||||
free(outBase64);
|
||||
return ret;
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
78
cocos/base/StringUtil.h
Normal file
78
cocos/base/StringUtil.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include "Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class CC_DLL StringUtil {
|
||||
public:
|
||||
static int vprintf(char *buf, const char *last, const char *fmt, va_list args);
|
||||
static int printf(char *buf, const char *last, const char *fmt, ...);
|
||||
static ccstd::string format(const char *fmt, ...);
|
||||
static ccstd::vector<ccstd::string> split(const ccstd::string &str, const ccstd::string &delims, uint32_t maxSplits = 0);
|
||||
static ccstd::string &replace(ccstd::string &str, const ccstd::string &findStr, const ccstd::string &replaceStr);
|
||||
static ccstd::string &replaceAll(ccstd::string &str, const ccstd::string &findStr, const ccstd::string &replaceStr);
|
||||
static ccstd::string &tolower(ccstd::string &str);
|
||||
static ccstd::string &toupper(ccstd::string &str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Store compressed text which compressed with gzip & base64
|
||||
* fetch plain-text with `value()`.
|
||||
*/
|
||||
class CC_DLL GzipedString {
|
||||
public:
|
||||
explicit GzipedString(ccstd::string &&dat) : _str(dat) {}
|
||||
explicit GzipedString(const char *dat) : _str(dat) {}
|
||||
GzipedString(const GzipedString &o) = default;
|
||||
GzipedString &operator=(const GzipedString &d) = default;
|
||||
|
||||
GzipedString(GzipedString &&o) noexcept {
|
||||
_str = std::move(o._str);
|
||||
}
|
||||
GzipedString &operator=(ccstd::string &&d) {
|
||||
_str = std::move(d);
|
||||
return *this;
|
||||
}
|
||||
GzipedString &operator=(GzipedString &&d) noexcept {
|
||||
_str = std::move(d._str);
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* return text decompress with base64decode | un-gzip
|
||||
*/
|
||||
ccstd::string value() const;
|
||||
|
||||
private:
|
||||
ccstd::string _str{};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
47
cocos/base/TemplateUtils.h
Normal file
47
cocos/base/TemplateUtils.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
#pragma once
|
||||
|
||||
namespace cc {
|
||||
|
||||
/* overloaded is used in ccstd::visit a variant value. For example:
|
||||
|
||||
ccstd::variant<ccstd::monostate, int, bool, float> value;
|
||||
ccstd::visit(cc::overloaded{
|
||||
[](auto& v) {
|
||||
// Do something with v
|
||||
},
|
||||
[](ccstd::monostate&) {} // Do nothing if value isn't initialized
|
||||
}, value);
|
||||
|
||||
*/
|
||||
|
||||
// https://stackoverflow.com/questions/69915380/what-does-templateclass-ts-struct-overloaded-ts-using-tsoperator
|
||||
// https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
|
||||
template <class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
} // namespace cc
|
||||
380
cocos/base/ThreadPool.cpp
Normal file
380
cocos/base/ThreadPool.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016-2017 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/ThreadPool.h"
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include "base/memory/Memory.h"
|
||||
#include "platform/StdC.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#define LOG_TAG "ThreadPool"
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define LOGD(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define TIME_MINUS(now, prev) (std::chrono::duration_cast<std::chrono::milliseconds>((now) - (prev)).count() / 1000.0f)
|
||||
|
||||
namespace cc {
|
||||
|
||||
#define DEFAULT_THREAD_POOL_MIN_NUM (4)
|
||||
#define DEFAULT_THREAD_POOL_MAX_NUM (20)
|
||||
|
||||
#define DEFAULT_SHRINK_INTERVAL (5)
|
||||
#define DEFAULT_SHRINK_STEP (2)
|
||||
#define DEFAULT_STRETCH_STEP (2)
|
||||
|
||||
LegacyThreadPool *LegacyThreadPool::_instance = nullptr;
|
||||
|
||||
LegacyThreadPool *LegacyThreadPool::getDefaultThreadPool() {
|
||||
if (LegacyThreadPool::_instance == nullptr) {
|
||||
LegacyThreadPool::_instance = newCachedThreadPool(DEFAULT_THREAD_POOL_MIN_NUM,
|
||||
DEFAULT_THREAD_POOL_MAX_NUM,
|
||||
DEFAULT_SHRINK_INTERVAL, DEFAULT_SHRINK_STEP,
|
||||
DEFAULT_STRETCH_STEP);
|
||||
}
|
||||
|
||||
return LegacyThreadPool::_instance;
|
||||
}
|
||||
|
||||
void LegacyThreadPool::destroyDefaultThreadPool() {
|
||||
delete LegacyThreadPool::_instance;
|
||||
LegacyThreadPool::_instance = nullptr;
|
||||
}
|
||||
|
||||
LegacyThreadPool *LegacyThreadPool::newCachedThreadPool(int minThreadNum, int maxThreadNum, int shrinkInterval,
|
||||
int shrinkStep, int stretchStep) {
|
||||
auto *pool = ccnew LegacyThreadPool(minThreadNum, maxThreadNum);
|
||||
if (pool != nullptr) {
|
||||
pool->setFixedSize(false);
|
||||
pool->setShrinkInterval(shrinkInterval);
|
||||
pool->setShrinkStep(shrinkStep);
|
||||
pool->setStretchStep(stretchStep);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
LegacyThreadPool *LegacyThreadPool::newFixedThreadPool(int threadNum) {
|
||||
auto *pool = ccnew LegacyThreadPool(threadNum, threadNum);
|
||||
if (pool != nullptr) {
|
||||
pool->setFixedSize(true);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
LegacyThreadPool *LegacyThreadPool::newSingleThreadPool() {
|
||||
auto *pool = ccnew LegacyThreadPool(1, 1);
|
||||
if (pool != nullptr) {
|
||||
pool->setFixedSize(true);
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
LegacyThreadPool::LegacyThreadPool(int minNum, int maxNum)
|
||||
: _minThreadNum(minNum),
|
||||
_maxThreadNum(maxNum) {
|
||||
init();
|
||||
}
|
||||
|
||||
// the destructor waits for all the functions in the queue to be finished
|
||||
LegacyThreadPool::~LegacyThreadPool() {
|
||||
stop();
|
||||
}
|
||||
|
||||
// number of idle threads
|
||||
int LegacyThreadPool::getIdleThreadNum() const {
|
||||
auto *thiz = const_cast<LegacyThreadPool *>(this);
|
||||
std::lock_guard<std::mutex> lk(thiz->_idleThreadNumMutex);
|
||||
return _idleThreadNum;
|
||||
}
|
||||
|
||||
void LegacyThreadPool::init() {
|
||||
_lastShrinkTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
_maxThreadNum = std::max(_minThreadNum, _maxThreadNum);
|
||||
|
||||
_threads.resize(_maxThreadNum);
|
||||
_abortFlags.resize(_maxThreadNum);
|
||||
_idleFlags.resize(_maxThreadNum);
|
||||
_initedFlags.resize(_maxThreadNum);
|
||||
|
||||
for (int i = 0; i < _maxThreadNum; ++i) {
|
||||
_idleFlags[i] = std::make_shared<std::atomic<bool>>(false);
|
||||
if (i < _minThreadNum) {
|
||||
_abortFlags[i] = std::make_shared<std::atomic<bool>>(false);
|
||||
setThread(i);
|
||||
_initedFlags[i] = std::make_shared<std::atomic<bool>>(true);
|
||||
++_initedThreadNum;
|
||||
} else {
|
||||
_abortFlags[i] = std::make_shared<std::atomic<bool>>(true);
|
||||
_initedFlags[i] = std::make_shared<std::atomic<bool>>(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LegacyThreadPool::tryShrinkPool() {
|
||||
LOGD("shrink pool, _idleThreadNum = %d \n", getIdleThreadNum());
|
||||
|
||||
auto before = std::chrono::high_resolution_clock::now();
|
||||
|
||||
ccstd::vector<int> threadIDsToJoin;
|
||||
int maxThreadNumToJoin = std::min(_initedThreadNum - _minThreadNum, _shrinkStep);
|
||||
|
||||
for (int i = 0; i < _maxThreadNum; ++i) {
|
||||
if ((int)threadIDsToJoin.size() >= maxThreadNumToJoin) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (*_idleFlags[i]) {
|
||||
*_abortFlags[i] = true;
|
||||
threadIDsToJoin.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// stop the detached threads that were waiting
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cv.notify_all();
|
||||
}
|
||||
|
||||
for (const auto &threadID : threadIDsToJoin) { // wait for the computing threads to finish
|
||||
if (_threads[threadID]->joinable()) {
|
||||
_threads[threadID]->join();
|
||||
}
|
||||
|
||||
_threads[threadID].reset();
|
||||
*_initedFlags[threadID] = false;
|
||||
--_initedThreadNum;
|
||||
}
|
||||
|
||||
auto after = std::chrono::high_resolution_clock::now();
|
||||
|
||||
float seconds = TIME_MINUS(after, before);
|
||||
|
||||
LOGD("shrink %d threads, waste: %f seconds\n", (int)threadIDsToJoin.size(), seconds);
|
||||
|
||||
return (_initedThreadNum <= _minThreadNum);
|
||||
}
|
||||
|
||||
void LegacyThreadPool::stretchPool(int count) {
|
||||
auto before = std::chrono::high_resolution_clock::now();
|
||||
|
||||
int oldThreadCount = _initedThreadNum;
|
||||
int newThreadCount = 0;
|
||||
|
||||
for (int i = 0; i < _maxThreadNum; ++i) {
|
||||
if (!*_initedFlags[i]) {
|
||||
*_abortFlags[i] = false;
|
||||
setThread(i);
|
||||
*_initedFlags[i] = true;
|
||||
++_initedThreadNum;
|
||||
|
||||
if (++newThreadCount >= count) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newThreadCount > 0) {
|
||||
auto after = std::chrono::high_resolution_clock::now();
|
||||
float seconds = TIME_MINUS(after, before);
|
||||
|
||||
LOGD("stretch pool from %d to %d, waste %f seconds\n", oldThreadCount, _initedThreadNum,
|
||||
seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::pushTask(const std::function<void(int)> &runnable,
|
||||
TaskType type /* = DEFAULT*/) {
|
||||
if (!_isFixedSize) {
|
||||
_idleThreadNumMutex.lock();
|
||||
int idleNum = _idleThreadNum;
|
||||
_idleThreadNumMutex.unlock();
|
||||
|
||||
if (idleNum > _minThreadNum) {
|
||||
if (_taskQueue.empty()) {
|
||||
auto now = std::chrono::high_resolution_clock::now();
|
||||
float seconds = TIME_MINUS(now, _lastShrinkTime);
|
||||
if (seconds > _shrinkInterval) {
|
||||
tryShrinkPool();
|
||||
_lastShrinkTime = now;
|
||||
}
|
||||
}
|
||||
} else if (idleNum == 0) {
|
||||
stretchPool(_stretchStep);
|
||||
}
|
||||
}
|
||||
|
||||
auto callback = ccnew std::function<void(int)>([runnable](int tid) {
|
||||
runnable(tid);
|
||||
});
|
||||
|
||||
Task task;
|
||||
task.type = type;
|
||||
task.callback = callback;
|
||||
_taskQueue.push(task);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::stopAllTasks() {
|
||||
Task task;
|
||||
while (_taskQueue.pop(task)) {
|
||||
delete task.callback; // empty the queue
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::stopTasksByType(TaskType type) {
|
||||
Task task;
|
||||
|
||||
ccstd::vector<Task> notStopTasks;
|
||||
notStopTasks.reserve(_taskQueue.size());
|
||||
|
||||
while (_taskQueue.pop(task)) {
|
||||
if (task.type == type) { // Delete the task from queue
|
||||
delete task.callback;
|
||||
} else { // If task type isn't match, push it into a vector, then insert to task queue again
|
||||
notStopTasks.push_back(task);
|
||||
}
|
||||
}
|
||||
|
||||
if (!notStopTasks.empty()) {
|
||||
for (const auto &t : notStopTasks) {
|
||||
_taskQueue.push(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::joinThread(int tid) {
|
||||
if (tid < 0 || tid >= (int)_threads.size()) {
|
||||
LOGD("Invalid thread id %d\n", tid);
|
||||
return;
|
||||
}
|
||||
|
||||
// wait for the computing threads to finish
|
||||
if (*_initedFlags[tid] && _threads[tid]->joinable()) {
|
||||
_threads[tid]->join();
|
||||
*_initedFlags[tid] = false;
|
||||
--_initedThreadNum;
|
||||
}
|
||||
}
|
||||
|
||||
int LegacyThreadPool::getTaskNum() const {
|
||||
return (int)_taskQueue.size();
|
||||
}
|
||||
|
||||
void LegacyThreadPool::setFixedSize(bool isFixedSize) {
|
||||
_isFixedSize = isFixedSize;
|
||||
}
|
||||
|
||||
void LegacyThreadPool::setShrinkInterval(int seconds) {
|
||||
if (seconds >= 0) {
|
||||
_shrinkInterval = static_cast<float>(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::setShrinkStep(int step) {
|
||||
if (step > 0) {
|
||||
_shrinkStep = step;
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::setStretchStep(int step) {
|
||||
if (step > 0) {
|
||||
_stretchStep = step;
|
||||
}
|
||||
}
|
||||
|
||||
void LegacyThreadPool::stop() {
|
||||
if (_isDone || _isStop) {
|
||||
return;
|
||||
}
|
||||
|
||||
_isDone = true; // give the waiting threads a command to finish
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_cv.notify_all(); // stop all waiting threads
|
||||
}
|
||||
|
||||
for (int i = 0, n = static_cast<int>(_threads.size()); i < n; ++i) {
|
||||
joinThread(i);
|
||||
}
|
||||
// if there were no threads in the pool but some functors in the queue, the functors are not deleted by the threads
|
||||
// therefore delete them here
|
||||
stopAllTasks();
|
||||
_threads.clear();
|
||||
_abortFlags.clear();
|
||||
}
|
||||
|
||||
void LegacyThreadPool::setThread(int tid) {
|
||||
std::shared_ptr<std::atomic<bool>> abortPtr(
|
||||
_abortFlags[tid]); // a copy of the shared ptr to the flag
|
||||
auto f = [this, tid, abortPtr /* a copy of the shared ptr to the abort */]() {
|
||||
std::atomic<bool> &abort = *abortPtr;
|
||||
Task task;
|
||||
bool isPop = _taskQueue.pop(task);
|
||||
while (true) {
|
||||
while (isPop) { // if there is anything in the queue
|
||||
std::unique_ptr<std::function<void(int)>> func(
|
||||
task.callback); // at return, delete the function even if an exception occurred
|
||||
(*task.callback)(tid);
|
||||
if (abort) {
|
||||
return; // the thread is wanted to stop, return even if the queue is not empty yet
|
||||
}
|
||||
|
||||
isPop = _taskQueue.pop(task);
|
||||
}
|
||||
// the queue is empty here, wait for the next command
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_idleThreadNumMutex.lock();
|
||||
++_idleThreadNum;
|
||||
_idleThreadNumMutex.unlock();
|
||||
|
||||
*_idleFlags[tid] = true;
|
||||
_cv.wait(lock, [this, &task, &isPop, &abort]() {
|
||||
isPop = _taskQueue.pop(task);
|
||||
return isPop || _isDone || abort;
|
||||
});
|
||||
*_idleFlags[tid] = false;
|
||||
_idleThreadNumMutex.lock();
|
||||
--_idleThreadNum;
|
||||
_idleThreadNumMutex.unlock();
|
||||
|
||||
if (!isPop) {
|
||||
return; // if the queue is empty and isDone == true or *flag then return
|
||||
}
|
||||
}
|
||||
};
|
||||
_threads[tid].reset(
|
||||
ccnew std::thread(f)); // compiler may not support std::make_unique()
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
216
cocos/base/ThreadPool.h
Normal file
216
cocos/base/ThreadPool.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2016-2017 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "base/Utils.h"
|
||||
#include "base/std/container/queue.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class CC_DLL LegacyThreadPool {
|
||||
public:
|
||||
enum class TaskType {
|
||||
DEFAULT = 0,
|
||||
NETWORK,
|
||||
IO,
|
||||
AUDIO,
|
||||
USER = 1000
|
||||
};
|
||||
|
||||
/*
|
||||
* Gets the default thread pool which is a cached thread pool with default parameters.
|
||||
*/
|
||||
static LegacyThreadPool *getDefaultThreadPool();
|
||||
|
||||
/*
|
||||
* Destroys the default thread pool
|
||||
*/
|
||||
static void destroyDefaultThreadPool();
|
||||
|
||||
/*
|
||||
* Creates a cached thread pool
|
||||
* @note The return value has to be delete while it doesn't needed
|
||||
*/
|
||||
static LegacyThreadPool *newCachedThreadPool(int minThreadNum, int maxThreadNum, int shrinkInterval,
|
||||
int shrinkStep, int stretchStep);
|
||||
|
||||
/*
|
||||
* Creates a thread pool with fixed thread count
|
||||
* @note The return value has to be delete while it doesn't needed
|
||||
*/
|
||||
static LegacyThreadPool *newFixedThreadPool(int threadNum);
|
||||
|
||||
/*
|
||||
* Creates a thread pool with only one thread in the pool, it could be used to execute multiply tasks serially in just one thread.
|
||||
* @note The return value has to be delete while it doesn't needed
|
||||
*/
|
||||
static LegacyThreadPool *newSingleThreadPool();
|
||||
|
||||
// the destructor waits for all the functions in the queue to be finished
|
||||
~LegacyThreadPool();
|
||||
|
||||
/* Pushs a task to thread pool
|
||||
* @param runnable The callback of the task executed in sub thread
|
||||
* @param type The task type, it's TASK_TYPE_DEFAULT if this argument isn't assigned
|
||||
* @note This function has to be invoked in cocos thread
|
||||
*/
|
||||
void pushTask(const std::function<void(int /*threadId*/)> &runnable, TaskType type = TaskType::DEFAULT);
|
||||
|
||||
// Stops all tasks, it will remove all tasks in queue
|
||||
void stopAllTasks();
|
||||
|
||||
// Stops some tasks by type
|
||||
void stopTasksByType(TaskType type);
|
||||
|
||||
// Gets the minimum thread numbers
|
||||
inline int getMinThreadNum() const { return _minThreadNum; };
|
||||
|
||||
// Gets the maximum thread numbers
|
||||
inline int getMaxThreadNum() const { return _maxThreadNum; };
|
||||
|
||||
// Gets the number of idle threads
|
||||
int getIdleThreadNum() const;
|
||||
|
||||
// Gets the number of initialized threads
|
||||
inline int getInitedThreadNum() const { return _initedThreadNum; };
|
||||
|
||||
// Gets the task number
|
||||
int getTaskNum() const;
|
||||
|
||||
/*
|
||||
* Trys to shrink pool
|
||||
* @note This method is only available for cached thread pool
|
||||
*/
|
||||
bool tryShrinkPool();
|
||||
|
||||
private:
|
||||
LegacyThreadPool(int minNum, int maxNum);
|
||||
|
||||
LegacyThreadPool(const LegacyThreadPool &);
|
||||
|
||||
LegacyThreadPool(LegacyThreadPool &&) noexcept;
|
||||
|
||||
LegacyThreadPool &operator=(const LegacyThreadPool &);
|
||||
|
||||
LegacyThreadPool &operator=(LegacyThreadPool &&) noexcept;
|
||||
|
||||
void init();
|
||||
|
||||
void stop();
|
||||
|
||||
void setThread(int tid);
|
||||
|
||||
void joinThread(int tid);
|
||||
|
||||
void setFixedSize(bool isFixedSize);
|
||||
|
||||
void setShrinkInterval(int seconds);
|
||||
|
||||
void setShrinkStep(int step);
|
||||
|
||||
void setStretchStep(int step);
|
||||
|
||||
void stretchPool(int count);
|
||||
|
||||
ccstd::vector<std::unique_ptr<std::thread>> _threads;
|
||||
ccstd::vector<std::shared_ptr<std::atomic<bool>>> _abortFlags;
|
||||
ccstd::vector<std::shared_ptr<std::atomic<bool>>> _idleFlags;
|
||||
ccstd::vector<std::shared_ptr<std::atomic<bool>>> _initedFlags;
|
||||
|
||||
template <typename T>
|
||||
class ThreadSafeQueue {
|
||||
public:
|
||||
bool push(T const &value) {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
this->q.push(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
// deletes the retrieved element, do not use for non integral types
|
||||
bool pop(T &v) {
|
||||
std::unique_lock<std::mutex> lock(this->mutex);
|
||||
if (this->q.empty())
|
||||
return false;
|
||||
v = this->q.front();
|
||||
this->q.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
auto thiz = const_cast<ThreadSafeQueue *>(this);
|
||||
std::unique_lock<std::mutex> lock(thiz->mutex);
|
||||
return this->q.empty();
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
auto thiz = const_cast<ThreadSafeQueue *>(this);
|
||||
std::unique_lock<std::mutex> lock(thiz->mutex);
|
||||
return this->q.size();
|
||||
}
|
||||
|
||||
private:
|
||||
ccstd::queue<T> q;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
struct Task {
|
||||
TaskType type;
|
||||
std::function<void(int)> *callback;
|
||||
};
|
||||
|
||||
static LegacyThreadPool *_instance;
|
||||
|
||||
ThreadSafeQueue<Task> _taskQueue;
|
||||
std::atomic<bool> _isDone{false};
|
||||
std::atomic<bool> _isStop{false};
|
||||
|
||||
//IDEA: std::atomic<int> isn't supported by ndk-r10e while compiling with `armeabi` arch.
|
||||
// So using a mutex here instead.
|
||||
int _idleThreadNum{0}; // how many threads are waiting
|
||||
std::mutex _idleThreadNumMutex;
|
||||
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _cv;
|
||||
|
||||
int _minThreadNum{0};
|
||||
int _maxThreadNum{0};
|
||||
int _initedThreadNum{0};
|
||||
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> _lastShrinkTime;
|
||||
float _shrinkInterval{5};
|
||||
int _shrinkStep{2};
|
||||
int _stretchStep{2};
|
||||
bool _isFixedSize{false};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
71
cocos/base/Timer.cpp
Normal file
71
cocos/base/Timer.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
namespace cc {
|
||||
namespace utils {
|
||||
|
||||
Timer::Timer(bool doReset) {
|
||||
if (doReset) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Timer::reset() {
|
||||
_startTime = Clock::now();
|
||||
}
|
||||
|
||||
int64_t Timer::getMicroseconds() const {
|
||||
auto currentTime = Clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(currentTime - _startTime).count();
|
||||
if (duration < 0) {
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
int64_t Timer::getMilliseconds() const {
|
||||
auto currentTime = Clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - _startTime).count();
|
||||
if (duration < 0) {
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
return duration;
|
||||
}
|
||||
|
||||
float Timer::getSeconds(bool highPrecision) const {
|
||||
if (highPrecision) {
|
||||
int64_t micro = getMicroseconds();
|
||||
return static_cast<float>(micro) / 1000000.0F;
|
||||
}
|
||||
|
||||
int64_t milli = getMilliseconds();
|
||||
return static_cast<float>(milli) / 1000.0F;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
} // namespace cc
|
||||
51
cocos/base/Timer.h
Normal file
51
cocos/base/Timer.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include "base/Macros.h"
|
||||
|
||||
namespace cc {
|
||||
namespace utils {
|
||||
|
||||
class CC_DLL Timer {
|
||||
public:
|
||||
using Clock = std::chrono::high_resolution_clock;
|
||||
using TimePoint = Clock::time_point;
|
||||
|
||||
explicit Timer(bool doReset = true);
|
||||
|
||||
void reset();
|
||||
int64_t getMicroseconds() const;
|
||||
int64_t getMilliseconds() const;
|
||||
float getSeconds(bool highPrecision = false) const;
|
||||
|
||||
private:
|
||||
TimePoint _startTime;
|
||||
};
|
||||
|
||||
} // namespace utils
|
||||
} // namespace cc
|
||||
79
cocos/base/TypeDef.h
Normal file
79
cocos/base/TypeDef.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "base/Macros.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
|
||||
using uint = std::uint32_t;
|
||||
using ushort = std::uint16_t;
|
||||
|
||||
#if (CC_PLATFORM != CC_PLATFORM_LINUX && CC_PLATFORM != CC_PLATFORM_QNX && CC_PLATFORM != CC_PLATFORM_EMSCRIPTEN && CC_PLATFORM != CC_PLATFORM_OPENHARMONY) // linux and openharmony has typedef ulong
|
||||
using ulong = std::uint32_t;
|
||||
#endif
|
||||
using FlagBits = std::uint32_t;
|
||||
|
||||
using index_t = int32_t;
|
||||
#define CC_INVALID_INDEX (-1)
|
||||
|
||||
#define CC_ENUM_CONVERSION_OPERATOR(T) \
|
||||
inline std::underlying_type<T>::type toNumber(const T v) { return static_cast<std::underlying_type<T>::type>(v); }
|
||||
|
||||
#define CC_ENUM_BITWISE_OPERATORS(T) \
|
||||
constexpr bool operator!(const T v) { return !static_cast<std::underlying_type<T>::type>(v); } \
|
||||
constexpr T operator~(const T v) { return static_cast<T>(~static_cast<std::underlying_type<T>::type>(v)); } \
|
||||
constexpr bool operator||(const T lhs, const T rhs) { return (static_cast<std::underlying_type<T>::type>(lhs) || static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr bool operator&&(const T lhs, const T rhs) { return (static_cast<std::underlying_type<T>::type>(lhs) && static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr T operator|(const T lhs, const T rhs) { return static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) | static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr T operator&(const T lhs, const T rhs) { return static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) & static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr T operator^(const T lhs, const T rhs) { return static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) ^ static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr T operator+(const T lhs, const T rhs) { return static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) + static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr T operator+(const T lhs, bool rhs) { return static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) + rhs); } \
|
||||
constexpr void operator|=(T &lhs, const T rhs) { lhs = static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) | static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr void operator&=(T &lhs, const T rhs) { lhs = static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) & static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr void operator^=(T &lhs, const T rhs) { lhs = static_cast<T>(static_cast<std::underlying_type<T>::type>(lhs) ^ static_cast<std::underlying_type<T>::type>(rhs)); } \
|
||||
constexpr bool hasFlag(const T flags, const T flagToTest) { \
|
||||
using ValueType = std::underlying_type<T>::type; \
|
||||
CC_ASSERT((static_cast<ValueType>(flagToTest) & (static_cast<ValueType>(flagToTest) - 1)) == 0); \
|
||||
return (static_cast<ValueType>(flags) & static_cast<ValueType>(flagToTest)) != 0; \
|
||||
} \
|
||||
constexpr bool hasAnyFlags(const T flags, const T flagsToTest) { \
|
||||
using ValueType = std::underlying_type<T>::type; \
|
||||
return (static_cast<ValueType>(flags) & static_cast<ValueType>(flagsToTest)) != 0; \
|
||||
} \
|
||||
constexpr bool hasAllFlags(const T flags, const T flagsToTest) { \
|
||||
using ValueType = std::underlying_type<T>::type; \
|
||||
return (static_cast<ValueType>(flags) & static_cast<ValueType>(flagsToTest)) == static_cast<ValueType>(flagsToTest); \
|
||||
} \
|
||||
constexpr T addFlags(T &flags, const T flagsToAdd) { \
|
||||
flags |= flagsToAdd; \
|
||||
return flags; \
|
||||
} \
|
||||
constexpr T removeFlags(T &flags, const T flagsToRemove) { \
|
||||
flags &= ~flagsToRemove; \
|
||||
return flags; \
|
||||
} \
|
||||
CC_ENUM_CONVERSION_OPERATOR(T)
|
||||
347
cocos/base/UTF8.cpp
Normal file
347
cocos/base/UTF8.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014 cocos2d-x.org
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/UTF8.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "ConvertUTF/ConvertUTF.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace StringUtils { //NOLINT
|
||||
|
||||
ccstd::string format(const char *format, ...) {
|
||||
#define CC_MAX_STRING_LENGTH (1024 * 100)
|
||||
|
||||
ccstd::string ret;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
|
||||
char *buf = static_cast<char *>(malloc(CC_MAX_STRING_LENGTH));
|
||||
if (buf != nullptr) {
|
||||
vsnprintf(buf, CC_MAX_STRING_LENGTH, format, ap);
|
||||
ret = buf;
|
||||
free(buf);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to search through.
|
||||
* @c: the character to not look for.
|
||||
*
|
||||
* Return value: the index of the last character that is not c.
|
||||
* */
|
||||
unsigned int getIndexOfLastNotChar16(const ccstd::vector<char16_t> &str, char16_t c) {
|
||||
int len = static_cast<int>(str.size());
|
||||
|
||||
int i = len - 1;
|
||||
for (; i >= 0; --i) {
|
||||
if (str[i] != c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* @str: the string to trim
|
||||
* @index: the index to start trimming from.
|
||||
*
|
||||
* Trims str st str=[0, index) after the operation.
|
||||
*
|
||||
* Return value: the trimmed string.
|
||||
* */
|
||||
static void trimUTF16VectorFromIndex(ccstd::vector<char16_t> &str, int index) { //NOLINT
|
||||
int size = static_cast<int>(str.size());
|
||||
if (index >= size || index < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
str.erase(str.begin() + index, str.begin() + size);
|
||||
}
|
||||
|
||||
/*
|
||||
* @ch is the unicode character whitespace?
|
||||
*
|
||||
* Reference: http://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
*
|
||||
* Return value: weather the character is a whitespace character.
|
||||
* */
|
||||
bool isUnicodeSpace(char16_t ch) {
|
||||
return (ch >= 0x0009 && ch <= 0x000D) || ch == 0x0020 || ch == 0x0085 || ch == 0x00A0 || ch == 0x1680 || (ch >= 0x2000 && ch <= 0x200A) || ch == 0x2028 || ch == 0x2029 || ch == 0x202F || ch == 0x205F || ch == 0x3000;
|
||||
}
|
||||
|
||||
bool isCJKUnicode(char16_t ch) {
|
||||
return (ch >= 0x4E00 && ch <= 0x9FBF) // CJK Unified Ideographs
|
||||
|| (ch >= 0x2E80 && ch <= 0x2FDF) // CJK Radicals Supplement & Kangxi Radicals
|
||||
|| (ch >= 0x2FF0 && ch <= 0x30FF) // Ideographic Description Characters, CJK Symbols and Punctuation & Japanese
|
||||
|| (ch >= 0x3100 && ch <= 0x31BF) // Korean
|
||||
|| (ch >= 0xAC00 && ch <= 0xD7AF) // Hangul Syllables
|
||||
|| (ch >= 0xF900 && ch <= 0xFAFF) // CJK Compatibility Ideographs
|
||||
|| (ch >= 0xFE30 && ch <= 0xFE4F) // CJK Compatibility Forms
|
||||
|| (ch >= 0x31C0 && ch <= 0x4DFF); // Other extensions
|
||||
}
|
||||
|
||||
void trimUTF16Vector(ccstd::vector<char16_t> &str) {
|
||||
int len = static_cast<int>(str.size());
|
||||
|
||||
if (len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lastIndex = len - 1;
|
||||
|
||||
// Only start trimming if the last character is whitespace..
|
||||
if (isUnicodeSpace(str[lastIndex])) {
|
||||
for (int i = lastIndex - 1; i >= 0; --i) {
|
||||
if (isUnicodeSpace(str[i])) {
|
||||
lastIndex = i;
|
||||
}
|
||||
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
trimUTF16VectorFromIndex(str, lastIndex);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct ConvertTrait {
|
||||
using ArgType = T;
|
||||
};
|
||||
template <>
|
||||
struct ConvertTrait<char> {
|
||||
using ArgType = UTF8;
|
||||
};
|
||||
template <>
|
||||
struct ConvertTrait<char16_t> {
|
||||
using ArgType = UTF16;
|
||||
};
|
||||
template <>
|
||||
struct ConvertTrait<char32_t> {
|
||||
using ArgType = UTF32;
|
||||
};
|
||||
|
||||
template <typename From, typename To, typename FromTrait = ConvertTrait<From>, typename ToTrait = ConvertTrait<To>>
|
||||
bool utfConvert(
|
||||
const std::basic_string<From> &from, std::basic_string<To> &to,
|
||||
ConversionResult (*cvtfunc)(const typename FromTrait::ArgType **, const typename FromTrait::ArgType *,
|
||||
typename ToTrait::ArgType **, typename ToTrait::ArgType *,
|
||||
ConversionFlags)) {
|
||||
static_assert(sizeof(From) == sizeof(typename FromTrait::ArgType), "Error size mismatched");
|
||||
static_assert(sizeof(To) == sizeof(typename ToTrait::ArgType), "Error size mismatched");
|
||||
|
||||
if (from.empty()) {
|
||||
to.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// See: http://unicode.org/faq/utf_bom.html#gen6
|
||||
constexpr int mostBytesPerCharacter = 4;
|
||||
|
||||
const size_t maxNumberOfChars = from.length(); // all UTFs at most one element represents one character.
|
||||
const size_t numberOfOut = maxNumberOfChars * mostBytesPerCharacter / sizeof(To);
|
||||
|
||||
std::basic_string<To> working(numberOfOut, 0);
|
||||
|
||||
auto inbeg = reinterpret_cast<const typename FromTrait::ArgType *>(&from[0]);
|
||||
auto inend = inbeg + from.length();
|
||||
|
||||
auto outbeg = reinterpret_cast<typename ToTrait::ArgType *>(&working[0]);
|
||||
auto outend = outbeg + working.length();
|
||||
auto r = cvtfunc(&inbeg, inend, &outbeg, outend, strictConversion);
|
||||
if (r != conversionOK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
working.resize(reinterpret_cast<To *>(outbeg) - &working[0]);
|
||||
to = std::move(working);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
CC_DLL void UTF8LooseFix(const ccstd::string &in, ccstd::string &out) { //NOLINT
|
||||
const auto *p = reinterpret_cast<const UTF8 *>(in.c_str());
|
||||
const auto *end = reinterpret_cast<const UTF8 *>(in.c_str() + in.size());
|
||||
unsigned ucharLen = 0;
|
||||
while (p < end) {
|
||||
ucharLen = getNumBytesForUTF8(*p);
|
||||
if (isLegalUTF8Sequence(p, p + ucharLen)) {
|
||||
if (p + ucharLen < end) {
|
||||
out.append(p, p + ucharLen);
|
||||
}
|
||||
p += ucharLen;
|
||||
} else {
|
||||
p += 1; //skip bad char
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UTF8ToUTF16(const ccstd::string &utf8, std::u16string &outUtf16) { //NOLINT
|
||||
return utfConvert(utf8, outUtf16, ConvertUTF8toUTF16);
|
||||
}
|
||||
|
||||
bool UTF8ToUTF32(const ccstd::string &utf8, std::u32string &outUtf32) { //NOLINT
|
||||
return utfConvert(utf8, outUtf32, ConvertUTF8toUTF32);
|
||||
}
|
||||
|
||||
bool UTF16ToUTF8(const std::u16string &utf16, ccstd::string &outUtf8) { //NOLINT
|
||||
return utfConvert(utf16, outUtf8, ConvertUTF16toUTF8);
|
||||
}
|
||||
|
||||
bool UTF16ToUTF32(const std::u16string &utf16, std::u32string &outUtf32) { //NOLINT
|
||||
return utfConvert(utf16, outUtf32, ConvertUTF16toUTF32);
|
||||
}
|
||||
|
||||
bool UTF32ToUTF8(const std::u32string &utf32, ccstd::string &outUtf8) { //NOLINT
|
||||
return utfConvert(utf32, outUtf8, ConvertUTF32toUTF8);
|
||||
}
|
||||
|
||||
bool UTF32ToUTF16(const std::u32string &utf32, std::u16string &outUtf16) { //NOLINT
|
||||
return utfConvert(utf32, outUtf16, ConvertUTF32toUTF16);
|
||||
}
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_ANDROID || CC_PLATFORM == CC_PLATFORM_OHOS)
|
||||
ccstd::string getStringUTFCharsJNI(JNIEnv *env, jstring srcjStr, bool *ret) {
|
||||
ccstd::string utf8Str;
|
||||
auto *unicodeChar = static_cast<const uint16_t *>(env->GetStringChars(srcjStr, nullptr));
|
||||
size_t unicodeCharLength = env->GetStringLength(srcjStr);
|
||||
const std::u16string unicodeStr(reinterpret_cast<const char16_t *>(unicodeChar), unicodeCharLength);
|
||||
bool flag = UTF16ToUTF8(unicodeStr, utf8Str);
|
||||
|
||||
if (ret) {
|
||||
*ret = flag;
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
utf8Str = "";
|
||||
}
|
||||
env->ReleaseStringChars(srcjStr, unicodeChar);
|
||||
return utf8Str;
|
||||
}
|
||||
|
||||
jstring newStringUTFJNI(JNIEnv *env, const ccstd::string &utf8Str, bool *ret) {
|
||||
std::u16string utf16Str;
|
||||
bool flag = cc::StringUtils::UTF8ToUTF16(utf8Str, utf16Str);
|
||||
|
||||
if (ret) {
|
||||
*ret = flag;
|
||||
}
|
||||
|
||||
if (!flag) {
|
||||
utf16Str.clear();
|
||||
}
|
||||
jstring stringText = env->NewString(reinterpret_cast<const jchar *>(utf16Str.data()), utf16Str.length());
|
||||
return stringText;
|
||||
}
|
||||
#endif
|
||||
|
||||
ccstd::vector<char16_t> getChar16VectorFromUTF16String(const std::u16string &utf16) {
|
||||
return ccstd::vector<char16_t>(utf16.begin(), utf16.end());
|
||||
}
|
||||
|
||||
long getCharacterCountInUTF8String(const ccstd::string &utf8) { //NOLINT
|
||||
return getUTF8StringLength(reinterpret_cast<const UTF8 *>(utf8.c_str()));
|
||||
}
|
||||
|
||||
StringUTF8::StringUTF8(const ccstd::string &newStr) {
|
||||
replace(newStr);
|
||||
}
|
||||
|
||||
std::size_t StringUTF8::length() const {
|
||||
return _str.size();
|
||||
}
|
||||
|
||||
void StringUTF8::replace(const ccstd::string &newStr) {
|
||||
_str.clear();
|
||||
if (!newStr.empty()) {
|
||||
const auto *sequenceUtf8 = reinterpret_cast<const UTF8 *>(newStr.c_str());
|
||||
|
||||
int lengthString = getUTF8StringLength(sequenceUtf8);
|
||||
|
||||
if (lengthString == 0) {
|
||||
CC_LOG_DEBUG("Bad utf-8 set string: %s", newStr.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
while (*sequenceUtf8) {
|
||||
std::size_t lengthChar = getNumBytesForUTF8(*sequenceUtf8);
|
||||
|
||||
CharUTF8 charUTF8;
|
||||
charUTF8._char.append(reinterpret_cast<const char *>(sequenceUtf8), lengthChar);
|
||||
sequenceUtf8 += lengthChar;
|
||||
|
||||
_str.push_back(charUTF8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::string StringUTF8::getAsCharSequence() const {
|
||||
ccstd::string charSequence;
|
||||
|
||||
for (auto &charUtf8 : _str) {
|
||||
charSequence.append(charUtf8._char);
|
||||
}
|
||||
|
||||
return charSequence;
|
||||
}
|
||||
|
||||
bool StringUTF8::deleteChar(std::size_t pos) {
|
||||
if (pos < _str.size()) {
|
||||
_str.erase(_str.begin() + pos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StringUTF8::insert(std::size_t pos, const ccstd::string &insertStr) {
|
||||
StringUTF8 utf8(insertStr);
|
||||
|
||||
return insert(pos, utf8);
|
||||
}
|
||||
|
||||
bool StringUTF8::insert(std::size_t pos, const StringUTF8 &insertStr) {
|
||||
if (pos <= _str.size()) {
|
||||
_str.insert(_str.begin() + pos, insertStr._str.begin(), insertStr._str.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace StringUtils
|
||||
|
||||
} // namespace cc
|
||||
216
cocos/base/UTF8.h
Normal file
216
cocos/base/UTF8.h
Normal file
@@ -0,0 +1,216 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2014 cocos2d-x.org
|
||||
Copyright (c) 2014-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include "base/Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_ANDROID || CC_PLATFORM == CC_PLATFORM_OHOS)
|
||||
#include "platform/java/jni/JniHelper.h"
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace StringUtils { //NOLINT
|
||||
|
||||
template <typename T>
|
||||
ccstd::string toString(T arg) {
|
||||
std::stringstream ss;
|
||||
ss << arg;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
ccstd::string CC_DLL format(const char *format, ...) CC_FORMAT_PRINTF(1, 2);
|
||||
|
||||
/**
|
||||
* @brief Converts from UTF8 string to UTF16 string.
|
||||
*
|
||||
* This function resizes \p outUtf16 to required size and
|
||||
* fill its contents with result UTF16 string if conversion success.
|
||||
* If conversion fails it guarantees not to change \p outUtf16.
|
||||
*
|
||||
* @param inUtf8 The source UTF8 string to be converted from.
|
||||
* @param outUtf16 The output string to hold the result UTF16s.
|
||||
* @return True if succeed, otherwise false.
|
||||
* @note Please check the return value before using \p outUtf16
|
||||
* e.g.
|
||||
* @code
|
||||
* std::u16string utf16;
|
||||
* bool ret = StringUtils::UTF8ToUTF16("你好hello", utf16);
|
||||
* if (ret) {
|
||||
* do_some_thing_with_utf16(utf16);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
CC_DLL bool UTF8ToUTF16(const ccstd::string &inUtf8, std::u16string &outUtf16); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Same as \a UTF8ToUTF16 but converts form UTF8 to UTF32.
|
||||
*
|
||||
* @see UTF8ToUTF16
|
||||
*/
|
||||
CC_DLL bool UTF8ToUTF32(const ccstd::string &inUtf8, std::u32string &outUtf32); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Same as \a UTF8ToUTF16 but converts form UTF16 to UTF8.
|
||||
*
|
||||
* @see UTF8ToUTF16
|
||||
*/
|
||||
CC_DLL bool UTF16ToUTF8(const std::u16string &inUtf16, ccstd::string &outUtf8); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Same as \a UTF8ToUTF16 but converts form UTF16 to UTF32.
|
||||
*
|
||||
* @see UTF8ToUTF16
|
||||
*/
|
||||
CC_DLL bool UTF16ToUTF32(const std::u16string &inUtf16, std::u32string &outUtf32); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Same as \a UTF8ToUTF16 but converts form UTF32 to UTF8.
|
||||
*
|
||||
* @see UTF8ToUTF16
|
||||
*/
|
||||
CC_DLL bool UTF32ToUTF8(const std::u32string &inUtf32, ccstd::string &outUtf8); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Same as \a UTF8ToUTF16 but converts form UTF32 to UTF16.
|
||||
*
|
||||
* @see UTF8ToUTF16
|
||||
*/
|
||||
CC_DLL bool UTF32ToUTF16(const std::u32string &inUtf32, std::u16string &outUtf16); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Skip some bad char code.
|
||||
*/
|
||||
CC_DLL void UTF8LooseFix(const ccstd::string &in, ccstd::string &out); //NOLINT
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_ANDROID || CC_PLATFORM == CC_PLATFORM_OHOS)
|
||||
|
||||
/**
|
||||
* @brief convert jstring to utf8 ccstd::string, same function with env->getStringUTFChars.
|
||||
* because getStringUTFChars can not pass special emoticon
|
||||
* @param env The JNI Env
|
||||
* @param srcjStr The jstring which want to convert
|
||||
* @param ret True if the conversion succeeds and the ret pointer isn't null
|
||||
* @returns the result of utf8 string
|
||||
*/
|
||||
CC_DLL ccstd::string getStringUTFCharsJNI(JNIEnv *env, jstring srcjStr, bool *ret = nullptr);
|
||||
|
||||
/**
|
||||
* @brief create a jstring with utf8 ccstd::string, same function with env->newStringUTF
|
||||
* because newStringUTF can not convert special emoticon
|
||||
* @param env The JNI Env
|
||||
* @param srcjStr The ccstd::string which want to convert
|
||||
* @param ret True if the conversion succeeds and the ret pointer isn't null
|
||||
* @returns the result of jstring,the jstring need to DeleteLocalRef(jstring);
|
||||
*/
|
||||
CC_DLL jstring newStringUTFJNI(JNIEnv *env, const ccstd::string &utf8Str, bool *ret = nullptr);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Trims the unicode spaces at the end of char16_t vector.
|
||||
*/
|
||||
CC_DLL void trimUTF16Vector(ccstd::vector<char16_t> &str); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Whether the character is a whitespace character.
|
||||
* @param ch The unicode character.
|
||||
* @returns Whether the character is a white space character.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Whitespace_character#Unicode
|
||||
*
|
||||
*/
|
||||
CC_DLL bool isUnicodeSpace(char16_t ch);
|
||||
|
||||
/**
|
||||
* @brief Whether the character is a Chinese/Japanese/Korean character.
|
||||
* @param ch The unicode character.
|
||||
* @returns Whether the character is a Chinese character.
|
||||
*
|
||||
* @see http://www.searchtb.com/2012/04/chinese_encode.html
|
||||
* @see http://tieba.baidu.com/p/748765987
|
||||
*
|
||||
*/
|
||||
CC_DLL bool isCJKUnicode(char16_t ch);
|
||||
|
||||
/**
|
||||
* @brief Returns the length of the string in characters.
|
||||
* @param utf8 An UTF-8 encoded string.
|
||||
* @returns The length of the string in characters.
|
||||
*/
|
||||
CC_DLL long getCharacterCountInUTF8String(const ccstd::string &utf8); //NOLINT
|
||||
|
||||
/**
|
||||
* @brief Gets the index of the last character that is not equal to the character given.
|
||||
* @param str The string to be searched.
|
||||
* @param c The character to be searched for.
|
||||
* @returns The index of the last character that is not \p c.
|
||||
*/
|
||||
CC_DLL unsigned int getIndexOfLastNotChar16(const ccstd::vector<char16_t> &str, char16_t c);
|
||||
|
||||
/**
|
||||
* @brief Gets char16_t vector from a given utf16 string.
|
||||
*/
|
||||
CC_DLL ccstd::vector<char16_t> getChar16VectorFromUTF16String(const std::u16string &utf16);
|
||||
|
||||
/**
|
||||
* Utf8 sequence
|
||||
* Store all utf8 chars as ccstd::string
|
||||
* Build from ccstd::string
|
||||
*/
|
||||
class CC_DLL StringUTF8 {
|
||||
public:
|
||||
struct CharUTF8 {
|
||||
ccstd::string _char;
|
||||
bool isAnsi() { return _char.size() == 1; }
|
||||
};
|
||||
using CharUTF8Store = ccstd::vector<CharUTF8>;
|
||||
|
||||
StringUTF8() = default;
|
||||
explicit StringUTF8(const ccstd::string &newStr);
|
||||
~StringUTF8() = default;
|
||||
|
||||
std::size_t length() const;
|
||||
void replace(const ccstd::string &newStr);
|
||||
|
||||
ccstd::string getAsCharSequence() const;
|
||||
|
||||
bool deleteChar(std::size_t pos);
|
||||
bool insert(std::size_t pos, const ccstd::string &insertStr);
|
||||
bool insert(std::size_t pos, const StringUTF8 &insertStr);
|
||||
|
||||
CharUTF8Store &getString() { return _str; }
|
||||
|
||||
private:
|
||||
CharUTF8Store _str;
|
||||
};
|
||||
|
||||
} // namespace StringUtils
|
||||
|
||||
} // namespace cc
|
||||
96
cocos/base/Utils.cpp
Normal file
96
cocos/base/Utils.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Utils.h"
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
||||
#include "boost/stacktrace.hpp"
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/memory/MemoryHook.h"
|
||||
#include "platform/FileUtils.h"
|
||||
|
||||
namespace cc {
|
||||
namespace utils {
|
||||
|
||||
#define MAX_ITOA_BUFFER_SIZE 256
|
||||
double atof(const char *str) {
|
||||
if (str == nullptr) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
char buf[MAX_ITOA_BUFFER_SIZE];
|
||||
strncpy(buf, str, MAX_ITOA_BUFFER_SIZE);
|
||||
|
||||
// strip string, only remain 7 numbers after '.'
|
||||
char *dot = strchr(buf, '.');
|
||||
if (dot != nullptr && dot - buf + 8 < MAX_ITOA_BUFFER_SIZE) {
|
||||
dot[8] = '\0';
|
||||
}
|
||||
|
||||
return ::atof(buf);
|
||||
}
|
||||
|
||||
uint32_t nextPOT(uint32_t x) {
|
||||
x = x - 1;
|
||||
x = x | (x >> 1);
|
||||
x = x | (x >> 2);
|
||||
x = x | (x >> 4);
|
||||
x = x | (x >> 8);
|
||||
x = x | (x >> 16);
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
// painfully slow to execute, use with caution
|
||||
ccstd::string getStacktrace(uint32_t skip, uint32_t maxDepth) {
|
||||
return boost::stacktrace::to_string(boost::stacktrace::stacktrace(skip, maxDepth));
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
#if USE_MEMORY_LEAK_DETECTOR
|
||||
|
||||
// Make sure GMemoryHook to be initialized first.
|
||||
#if (CC_COMPILER == CC_COMPILER_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4073)
|
||||
#pragma init_seg(lib)
|
||||
MemoryHook GMemoryHook;
|
||||
#pragma warning(pop)
|
||||
#elif (CC_COMPILER == CC_COMPILER_GNUC || CC_COMPILER == CC_COMPILER_CLANG)
|
||||
MemoryHook GMemoryHook __attribute__((init_priority(101)));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
} // namespace cc
|
||||
391
cocos/base/Utils.h
Normal file
391
cocos/base/Utils.h
Normal file
@@ -0,0 +1,391 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include "base/Macros.h"
|
||||
#include "base/TypeDef.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
/** @file ccUtils.h
|
||||
Misc free functions
|
||||
*/
|
||||
|
||||
namespace cc {
|
||||
namespace utils {
|
||||
|
||||
CC_DLL ccstd::string getStacktrace(uint32_t skip = 0, uint32_t maxDepth = UINT32_MAX);
|
||||
|
||||
/**
|
||||
* Returns the Next Power of Two value.
|
||||
* Examples:
|
||||
* - If "value" is 15, it will return 16.
|
||||
* - If "value" is 16, it will return 16.
|
||||
* - If "value" is 17, it will return 32.
|
||||
* @param value The value to get next power of two.
|
||||
* @return Returns the next power of two value.
|
||||
* @since v0.99.5
|
||||
*/
|
||||
CC_DLL uint32_t nextPOT(uint32_t x);
|
||||
|
||||
/**
|
||||
* Same to ::atof, but strip the string, remain 7 numbers after '.' before call atof.
|
||||
* Why we need this? Because in android c++_static, atof ( and std::atof ) is unsupported for numbers have long decimal part and contain
|
||||
* several numbers can approximate to 1 ( like 90.099998474121094 ), it will return inf. This function is used to fix this bug.
|
||||
* @param str The string be to converted to double.
|
||||
* @return Returns converted value of a string.
|
||||
*/
|
||||
CC_DLL double atof(const char *str);
|
||||
|
||||
#pragma warning(disable : 4146)
|
||||
template <typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value>>
|
||||
inline T getLowestBit(T mask) {
|
||||
return mask & (-mask);
|
||||
}
|
||||
#pragma warning(default : 4146)
|
||||
|
||||
template <typename T, typename = typename std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value>>
|
||||
inline T clearLowestBit(T mask) {
|
||||
return mask & (mask - 1);
|
||||
}
|
||||
|
||||
// v must be power of 2
|
||||
inline uint32_t getBitPosition(uint32_t v) {
|
||||
if (!v) return 0;
|
||||
uint32_t c = 32;
|
||||
if (v & 0x0000FFFF) c -= 16;
|
||||
if (v & 0x00FF00FF) c -= 8;
|
||||
if (v & 0x0F0F0F0F) c -= 4;
|
||||
if (v & 0x33333333) c -= 2;
|
||||
if (v & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
// v must be power of 2
|
||||
inline uint64_t getBitPosition(uint64_t v) {
|
||||
if (!v) return 0;
|
||||
uint64_t c = 64;
|
||||
if (v & 0x00000000FFFFFFFFLL) c -= 32;
|
||||
if (v & 0x0000FFFF0000FFFFLL) c -= 16;
|
||||
if (v & 0x00FF00FF00FF00FFLL) c -= 8;
|
||||
if (v & 0x0F0F0F0F0F0F0F0FLL) c -= 4;
|
||||
if (v & 0x3333333333333333LL) c -= 2;
|
||||
if (v & 0x5555555555555555LL) c -= 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if_t<std::is_integral<T>::value>>
|
||||
inline size_t popcount(T mask) {
|
||||
return std::bitset<sizeof(T)>(mask).count();
|
||||
}
|
||||
|
||||
template <typename T, typename = typename std::enable_if_t<std::is_integral<T>::value>>
|
||||
inline T alignTo(T size, T alignment) {
|
||||
return ((size - 1) / alignment + 1) * alignment;
|
||||
}
|
||||
|
||||
template <uint size, uint alignment>
|
||||
constexpr uint ALIGN_TO = ((size - 1) / alignment + 1) * alignment;
|
||||
|
||||
template <class T>
|
||||
inline uint toUint(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "T must be numeric");
|
||||
|
||||
CC_ASSERT(static_cast<uintmax_t>(value) <= static_cast<uintmax_t>(std::numeric_limits<uint>::max()));
|
||||
|
||||
return static_cast<uint>(value);
|
||||
}
|
||||
|
||||
template <typename Map>
|
||||
Map &mergeToMap(Map &outMap, const Map &inMap) {
|
||||
for (const auto &e : inMap) {
|
||||
outMap.emplace(e.first, e.second);
|
||||
}
|
||||
return outMap;
|
||||
}
|
||||
|
||||
namespace numext {
|
||||
|
||||
template <typename Tgt, typename Src>
|
||||
CC_FORCE_INLINE Tgt bit_cast(const Src &src) { // NOLINT(readability-identifier-naming)
|
||||
// The behaviour of memcpy is not specified for non-trivially copyable types
|
||||
static_assert(std::is_trivially_copyable<Src>::value, "THIS_TYPE_IS_NOT_SUPPORTED");
|
||||
static_assert(std::is_trivially_copyable<Tgt>::value && std::is_default_constructible<Tgt>::value,
|
||||
"THIS_TYPE_IS_NOT_SUPPORTED");
|
||||
static_assert(sizeof(Src) == sizeof(Tgt), "THIS_TYPE_IS_NOT_SUPPORTED");
|
||||
|
||||
Tgt tgt;
|
||||
// Load src into registers first. This allows the memcpy to be elided by CUDA.
|
||||
const Src staged = src;
|
||||
memcpy(&tgt, &staged, sizeof(Tgt));
|
||||
return tgt;
|
||||
}
|
||||
|
||||
} // namespace numext
|
||||
|
||||
// Following the Arm ACLE arm_neon.h should also include arm_fp16.h but not all
|
||||
// compilers seem to follow this. We therefore include it explicitly.
|
||||
// See also: https://bugs.llvm.org/show_bug.cgi?id=47955
|
||||
#if defined(CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC)
|
||||
#include <arm_fp16.h>
|
||||
#endif
|
||||
|
||||
// Code from https://gitlab.com/libeigen/eigen/-/blob/master/Eigen/src/Core/arch/Default/Half.h#L586
|
||||
struct HalfRaw {
|
||||
constexpr HalfRaw() : x(0) {}
|
||||
#if defined(CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC)
|
||||
explicit HalfRaw(uint16_t raw) : x(numext::bit_cast<__fp16>(raw)) {
|
||||
}
|
||||
__fp16 x;
|
||||
#else
|
||||
explicit constexpr HalfRaw(uint16_t raw) : x(raw) {}
|
||||
uint16_t x; // NOLINT(modernize-use-default-member-init)
|
||||
#endif
|
||||
};
|
||||
|
||||
// Conversion routines, including fallbacks for the host or older CUDA.
|
||||
// Note that newer Intel CPUs (Haswell or newer) have vectorized versions of
|
||||
// these in hardware. If we need more performance on older/other CPUs, they are
|
||||
// also possible to vectorize directly.
|
||||
|
||||
CC_FORCE_INLINE HalfRaw rawUint16ToHalf(uint16_t x) {
|
||||
// We cannot simply do a "return HalfRaw(x)" here, because HalfRaw is union type
|
||||
// in the hip_fp16 header file, and that will trigger a compile error
|
||||
// On the other hand, having anything but a return statement also triggers a compile error
|
||||
// because this is constexpr function.
|
||||
// Fortunately, since we need to disable EIGEN_CONSTEXPR for GPU anyway, we can get out
|
||||
// of this catch22 by having separate bodies for GPU / non GPU
|
||||
#if defined(CC_HAS_GPU_FP16)
|
||||
HalfRaw h;
|
||||
h.x = x;
|
||||
return h;
|
||||
#else
|
||||
return HalfRaw(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
CC_FORCE_INLINE uint16_t rawHalfAsUint16(const HalfRaw &h) {
|
||||
// HIP/CUDA/Default have a member 'x' of type uint16_t.
|
||||
// For ARM64 native half, the member 'x' is of type __fp16, so we need to bit-cast.
|
||||
// For SYCL, cl::sycl::half is _Float16, so cast directly.
|
||||
#if defined(CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC)
|
||||
return numext::bit_cast<uint16_t>(h.x);
|
||||
#else
|
||||
return h.x;
|
||||
#endif
|
||||
}
|
||||
|
||||
union float32_bits {
|
||||
unsigned int u;
|
||||
float f;
|
||||
};
|
||||
|
||||
CC_FORCE_INLINE HalfRaw floatToHalf(float ff) {
|
||||
#if defined(CC_HAS_FP16_C)
|
||||
HalfRaw h;
|
||||
#ifdef _MSC_VER
|
||||
// MSVC does not have scalar instructions.
|
||||
h.x = _mm_extract_epi16(_mm_cvtps_ph(_mm_set_ss(ff), 0), 0);
|
||||
#else
|
||||
h.x = _cvtss_sh(ff, 0);
|
||||
#endif
|
||||
return h;
|
||||
|
||||
#elif defined(CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC)
|
||||
HalfRaw h;
|
||||
h.x = static_cast<__fp16>(ff);
|
||||
return h;
|
||||
|
||||
#else
|
||||
float32_bits f;
|
||||
f.f = ff;
|
||||
|
||||
const float32_bits f32infty = {255 << 23};
|
||||
const float32_bits f16max = {(127 + 16) << 23};
|
||||
const float32_bits denorm_magic = {((127 - 15) + (23 - 10) + 1) << 23}; // NOLINT(readability-identifier-naming)
|
||||
unsigned int sign_mask = 0x80000000U; // NOLINT
|
||||
HalfRaw o;
|
||||
o.x = static_cast<uint16_t>(0x0U);
|
||||
|
||||
unsigned int sign = f.u & sign_mask;
|
||||
f.u ^= sign;
|
||||
|
||||
// NOTE all the integer compares in this function can be safely
|
||||
// compiled into signed compares since all operands are below
|
||||
// 0x80000000. Important if you want fast straight SSE2 code
|
||||
// (since there's no unsigned PCMPGTD).
|
||||
|
||||
if (f.u >= f16max.u) { // result is Inf or NaN (all exponent bits set)
|
||||
o.x = (f.u > f32infty.u) ? 0x7e00 : 0x7c00; // NaN->qNaN and Inf->Inf
|
||||
} else { // (De)normalized number or zero
|
||||
if (f.u < (113 << 23)) { // resulting FP16 is subnormal or zero
|
||||
// use a magic value to align our 10 mantissa bits at the bottom of
|
||||
// the float. as long as FP addition is round-to-nearest-even this
|
||||
// just works.
|
||||
f.f += denorm_magic.f;
|
||||
|
||||
// and one integer subtract of the bias later, we have our final float!
|
||||
o.x = static_cast<uint16_t>(f.u - denorm_magic.u);
|
||||
} else {
|
||||
unsigned int mant_odd = (f.u >> 13) & 1; // NOLINT(readability-identifier-naming) // resulting mantissa is odd
|
||||
|
||||
// update exponent, rounding bias part 1
|
||||
// Equivalent to `f.u += ((unsigned int)(15 - 127) << 23) + 0xfff`, but
|
||||
// without arithmetic overflow.
|
||||
f.u += 0xc8000fffU;
|
||||
// rounding bias part 2
|
||||
f.u += mant_odd;
|
||||
// take the bits!
|
||||
o.x = static_cast<uint16_t>(f.u >> 13);
|
||||
}
|
||||
}
|
||||
|
||||
o.x |= static_cast<uint16_t>(sign >> 16);
|
||||
return o;
|
||||
#endif
|
||||
}
|
||||
|
||||
CC_FORCE_INLINE float halfToFloat(HalfRaw h) {
|
||||
#if defined(CC_HAS_FP16_C)
|
||||
#ifdef _MSC_VER
|
||||
// MSVC does not have scalar instructions.
|
||||
return _mm_cvtss_f32(_mm_cvtph_ps(_mm_set1_epi16(h.x)));
|
||||
#else
|
||||
return _cvtsh_ss(h.x);
|
||||
#endif
|
||||
#elif defined(CC_HAS_ARM64_FP16_SCALAR_ARITHMETIC)
|
||||
return static_cast<float>(h.x);
|
||||
#else
|
||||
const float32_bits magic = {113 << 23};
|
||||
const unsigned int shifted_exp = 0x7c00 << 13; // NOLINT(readability-identifier-naming) // exponent mask after shift
|
||||
float32_bits o;
|
||||
|
||||
o.u = (h.x & 0x7fff) << 13; // exponent/mantissa bits
|
||||
unsigned int exp = shifted_exp & o.u; // just the exponent
|
||||
o.u += (127 - 15) << 23; // exponent adjust
|
||||
|
||||
// handle exponent special cases
|
||||
if (exp == shifted_exp) { // Inf/NaN?
|
||||
o.u += (128 - 16) << 23; // extra exp adjust
|
||||
} else if (exp == 0) { // Zero/Denormal?
|
||||
o.u += 1 << 23; // extra exp adjust
|
||||
o.f -= magic.f; // renormalize
|
||||
}
|
||||
|
||||
o.u |= (h.x & 0x8000) << 16; // sign bit
|
||||
return o.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace array {
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 移除首个指定的数组元素。判定元素相等时相当于于使用了 `Array.prototype.indexOf`。
|
||||
* @en
|
||||
* Removes the first occurrence of a specific object from the array.
|
||||
* Decision of the equality of elements is similar to `Array.prototype.indexOf`.
|
||||
* @param array 数组。
|
||||
* @param value 待移除元素。
|
||||
*/
|
||||
template <typename T>
|
||||
bool remove(ccstd::vector<T> &array, T value) {
|
||||
auto iter = std::find(array.begin(), array.end(), value);
|
||||
if (iter != array.end()) {
|
||||
array.erase(iter);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 移除指定索引的数组元素。
|
||||
* @en
|
||||
* Removes the array item at the specified index.
|
||||
* @param array 数组。
|
||||
* @param index 待移除元素的索引。
|
||||
*/
|
||||
template <typename T>
|
||||
bool removeAt(ccstd::vector<T> &array, int32_t index) {
|
||||
if (index >= 0 && index < static_cast<int32_t>(array.size())) {
|
||||
array.erase(array.begin() + index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 移除指定索引的数组元素。
|
||||
* 此函数十分高效,但会改变数组的元素次序。
|
||||
* @en
|
||||
* Removes the array item at the specified index.
|
||||
* It's faster but the order of the array will be changed.
|
||||
* @param array 数组。
|
||||
* @param index 待移除元素的索引。
|
||||
*/
|
||||
template <typename T>
|
||||
bool fastRemoveAt(ccstd::vector<T> &array, int32_t index) {
|
||||
const auto length = static_cast<int32_t>(array.size());
|
||||
if (index < 0 || index >= length) {
|
||||
return false;
|
||||
}
|
||||
array[index] = array[length - 1];
|
||||
array.resize(length - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh
|
||||
* 移除首个指定的数组元素。判定元素相等时相当于于使用了 `Array.prototype.indexOf`。
|
||||
* 此函数十分高效,但会改变数组的元素次序。
|
||||
* @en
|
||||
* Removes the first occurrence of a specific object from the array.
|
||||
* Decision of the equality of elements is similar to `Array.prototype.indexOf`.
|
||||
* It's faster but the order of the array will be changed.
|
||||
* @param array 数组。
|
||||
* @param value 待移除元素。
|
||||
*/
|
||||
template <typename T>
|
||||
bool fastRemove(ccstd::vector<T> &array, T value) {
|
||||
auto iter = std::find(array.begin(), array.end(), value);
|
||||
if (iter != array.end()) {
|
||||
*iter = array[array.size() - 1];
|
||||
array.resize(array.size() - 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace array
|
||||
} // namespace utils
|
||||
} // namespace cc
|
||||
829
cocos/base/Value.cpp
Normal file
829
cocos/base/Value.cpp
Normal file
@@ -0,0 +1,829 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Value.h"
|
||||
|
||||
#include <memory.h>
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "base/Utils.h"
|
||||
#include "base/memory/Memory.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
const ValueVector VALUE_VECTOR_NULL;
|
||||
const ValueMap VALUE_MAP_NULL = {};
|
||||
const ValueMapIntKey VALUE_MAP_INT_KEY_NULL = {};
|
||||
|
||||
const Value Value::VALUE_NULL;
|
||||
|
||||
Value::Value()
|
||||
: _type(Type::NONE) {
|
||||
memset(&_field, 0, sizeof(_field));
|
||||
}
|
||||
|
||||
Value::Value(unsigned char v)
|
||||
: _type(Type::BYTE) {
|
||||
_field.byteVal = v;
|
||||
}
|
||||
|
||||
Value::Value(int v)
|
||||
: _type(Type::INTEGER) {
|
||||
_field.intVal = v;
|
||||
}
|
||||
|
||||
Value::Value(unsigned int v)
|
||||
: _type(Type::UNSIGNED) {
|
||||
_field.unsignedVal = v;
|
||||
}
|
||||
|
||||
Value::Value(float v)
|
||||
: _type(Type::FLOAT) {
|
||||
_field.floatVal = v;
|
||||
}
|
||||
|
||||
Value::Value(double v)
|
||||
: _type(Type::DOUBLE) {
|
||||
_field.doubleVal = v;
|
||||
}
|
||||
|
||||
Value::Value(bool v)
|
||||
: _type(Type::BOOLEAN) {
|
||||
_field.boolVal = v;
|
||||
}
|
||||
|
||||
Value::Value(const char *v)
|
||||
: _type(Type::STRING) {
|
||||
_field.strVal = ccnew ccstd::string();
|
||||
if (v) {
|
||||
*_field.strVal = v;
|
||||
}
|
||||
}
|
||||
|
||||
Value::Value(const ccstd::string &v)
|
||||
: _type(Type::STRING) {
|
||||
_field.strVal = ccnew ccstd::string();
|
||||
*_field.strVal = v;
|
||||
}
|
||||
|
||||
Value::Value(const ValueVector &v)
|
||||
: _type(Type::VECTOR) {
|
||||
_field.vectorVal = ccnew ValueVector();
|
||||
*_field.vectorVal = v;
|
||||
}
|
||||
|
||||
Value::Value(ValueVector &&v)
|
||||
: _type(Type::VECTOR) {
|
||||
_field.vectorVal = ccnew ValueVector();
|
||||
*_field.vectorVal = std::move(v);
|
||||
}
|
||||
|
||||
Value::Value(const ValueMap &v)
|
||||
: _type(Type::MAP) {
|
||||
_field.mapVal = ccnew ValueMap();
|
||||
*_field.mapVal = v;
|
||||
}
|
||||
|
||||
Value::Value(ValueMap &&v)
|
||||
: _type(Type::MAP) {
|
||||
_field.mapVal = ccnew ValueMap();
|
||||
*_field.mapVal = std::move(v);
|
||||
}
|
||||
|
||||
Value::Value(const ValueMapIntKey &v)
|
||||
: _type(Type::INT_KEY_MAP) {
|
||||
_field.intKeyMapVal = ccnew ValueMapIntKey();
|
||||
*_field.intKeyMapVal = v;
|
||||
}
|
||||
|
||||
Value::Value(ValueMapIntKey &&v)
|
||||
: _type(Type::INT_KEY_MAP) {
|
||||
_field.intKeyMapVal = ccnew ValueMapIntKey();
|
||||
*_field.intKeyMapVal = std::move(v);
|
||||
}
|
||||
|
||||
Value::Value(const Value &other) //NOLINT(misc-no-recursion)
|
||||
: _type(Type::NONE) {
|
||||
*this = other;
|
||||
}
|
||||
|
||||
Value::Value(Value &&other) noexcept
|
||||
: _type(Type::NONE) {
|
||||
*this = std::move(other);
|
||||
}
|
||||
|
||||
Value::~Value() {
|
||||
clear();
|
||||
}
|
||||
|
||||
Value &Value::operator=(const Value &other) { //NOLINT(misc-no-recursion)
|
||||
if (this != &other) {
|
||||
reset(other._type);
|
||||
|
||||
switch (other._type) {
|
||||
case Type::BYTE:
|
||||
_field.byteVal = other._field.byteVal;
|
||||
break;
|
||||
case Type::INTEGER:
|
||||
_field.intVal = other._field.intVal;
|
||||
break;
|
||||
case Type::UNSIGNED:
|
||||
_field.unsignedVal = other._field.unsignedVal;
|
||||
break;
|
||||
case Type::FLOAT:
|
||||
_field.floatVal = other._field.floatVal;
|
||||
break;
|
||||
case Type::DOUBLE:
|
||||
_field.doubleVal = other._field.doubleVal;
|
||||
break;
|
||||
case Type::BOOLEAN:
|
||||
_field.boolVal = other._field.boolVal;
|
||||
break;
|
||||
case Type::STRING:
|
||||
if (_field.strVal == nullptr) {
|
||||
_field.strVal = ccnew ccstd::string();
|
||||
}
|
||||
*_field.strVal = *other._field.strVal;
|
||||
break;
|
||||
case Type::VECTOR:
|
||||
if (_field.vectorVal == nullptr) {
|
||||
_field.vectorVal = ccnew ValueVector();
|
||||
}
|
||||
*_field.vectorVal = *other._field.vectorVal;
|
||||
break;
|
||||
case Type::MAP:
|
||||
if (_field.mapVal == nullptr) {
|
||||
_field.mapVal = ccnew ValueMap();
|
||||
}
|
||||
*_field.mapVal = *other._field.mapVal;
|
||||
break;
|
||||
case Type::INT_KEY_MAP:
|
||||
if (_field.intKeyMapVal == nullptr) {
|
||||
_field.intKeyMapVal = ccnew ValueMapIntKey();
|
||||
}
|
||||
*_field.intKeyMapVal = *other._field.intKeyMapVal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(Value &&other) noexcept {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
switch (other._type) {
|
||||
case Type::BYTE:
|
||||
_field.byteVal = other._field.byteVal;
|
||||
break;
|
||||
case Type::INTEGER:
|
||||
_field.intVal = other._field.intVal;
|
||||
break;
|
||||
case Type::UNSIGNED:
|
||||
_field.unsignedVal = other._field.unsignedVal;
|
||||
break;
|
||||
case Type::FLOAT:
|
||||
_field.floatVal = other._field.floatVal;
|
||||
break;
|
||||
case Type::DOUBLE:
|
||||
_field.doubleVal = other._field.doubleVal;
|
||||
break;
|
||||
case Type::BOOLEAN:
|
||||
_field.boolVal = other._field.boolVal;
|
||||
break;
|
||||
case Type::STRING:
|
||||
_field.strVal = other._field.strVal;
|
||||
break;
|
||||
case Type::VECTOR:
|
||||
_field.vectorVal = other._field.vectorVal;
|
||||
break;
|
||||
case Type::MAP:
|
||||
_field.mapVal = other._field.mapVal;
|
||||
break;
|
||||
case Type::INT_KEY_MAP:
|
||||
_field.intKeyMapVal = other._field.intKeyMapVal;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_type = other._type;
|
||||
|
||||
memset(&other._field, 0, sizeof(other._field));
|
||||
other._type = Type::NONE;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(unsigned char v) {
|
||||
reset(Type::BYTE);
|
||||
_field.byteVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(int v) {
|
||||
reset(Type::INTEGER);
|
||||
_field.intVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(unsigned int v) {
|
||||
reset(Type::UNSIGNED);
|
||||
_field.unsignedVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(float v) {
|
||||
reset(Type::FLOAT);
|
||||
_field.floatVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(double v) {
|
||||
reset(Type::DOUBLE);
|
||||
_field.doubleVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(bool v) {
|
||||
reset(Type::BOOLEAN);
|
||||
_field.boolVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const char *v) {
|
||||
reset(Type::STRING);
|
||||
*_field.strVal = v ? v : "";
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const ccstd::string &v) {
|
||||
reset(Type::STRING);
|
||||
*_field.strVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const ValueVector &v) {
|
||||
reset(Type::VECTOR);
|
||||
*_field.vectorVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(ValueVector &&v) {
|
||||
reset(Type::VECTOR);
|
||||
*_field.vectorVal = std::move(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const ValueMap &v) {
|
||||
reset(Type::MAP);
|
||||
*_field.mapVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(ValueMap &&v) {
|
||||
reset(Type::MAP);
|
||||
*_field.mapVal = std::move(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(const ValueMapIntKey &v) {
|
||||
reset(Type::INT_KEY_MAP);
|
||||
*_field.intKeyMapVal = v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Value &Value::operator=(ValueMapIntKey &&v) {
|
||||
reset(Type::INT_KEY_MAP);
|
||||
*_field.intKeyMapVal = std::move(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Value::operator!=(const Value &v) {
|
||||
return !(*this == v);
|
||||
}
|
||||
bool Value::operator!=(const Value &v) const { //NOLINT(misc-no-recursion)
|
||||
return !(*this == v);
|
||||
}
|
||||
|
||||
bool Value::operator==(const Value &v) {
|
||||
const auto &t = *this;
|
||||
return t == v;
|
||||
}
|
||||
bool Value::operator==(const Value &v) const { //NOLINT(misc-no-recursion)
|
||||
if (this == &v) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (v._type != this->_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->isNull()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case Type::BYTE: return v._field.byteVal == this->_field.byteVal;
|
||||
case Type::INTEGER: return v._field.intVal == this->_field.intVal;
|
||||
case Type::UNSIGNED: return v._field.unsignedVal == this->_field.unsignedVal;
|
||||
case Type::BOOLEAN: return v._field.boolVal == this->_field.boolVal;
|
||||
case Type::STRING: return *v._field.strVal == *this->_field.strVal;
|
||||
case Type::FLOAT: return std::abs(v._field.floatVal - this->_field.floatVal) <= FLT_EPSILON;
|
||||
case Type::DOUBLE: return std::abs(v._field.doubleVal - this->_field.doubleVal) <= DBL_EPSILON;
|
||||
case Type::VECTOR: {
|
||||
const auto &v1 = *(this->_field.vectorVal);
|
||||
const auto &v2 = *(v._field.vectorVal);
|
||||
const auto size = v1.size();
|
||||
if (size == v2.size()) {
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (v1[i] != v2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case Type::MAP: {
|
||||
const auto &map1 = *(this->_field.mapVal);
|
||||
const auto &map2 = *(v._field.mapVal);
|
||||
for (const auto &kvp : map1) { //NOLINT
|
||||
auto it = map2.find(kvp.first);
|
||||
if (it == map2.end() || it->second != kvp.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Type::INT_KEY_MAP: {
|
||||
const auto &map1 = *(this->_field.intKeyMapVal);
|
||||
const auto &map2 = *(v._field.intKeyMapVal);
|
||||
for (const auto &kvp : map1) { //NOLINT
|
||||
auto it = map2.find(kvp.first);
|
||||
if (it == map2.end() || it->second != kvp.second) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Convert value to a specified type
|
||||
unsigned char Value::asByte() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return _field.byteVal;
|
||||
}
|
||||
|
||||
if (_type == Type::INTEGER) {
|
||||
return static_cast<unsigned char>(_field.intVal);
|
||||
}
|
||||
|
||||
if (_type == Type::UNSIGNED) {
|
||||
return static_cast<unsigned char>(_field.unsignedVal);
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return static_cast<unsigned char>(atoi(_field.strVal->c_str()));
|
||||
}
|
||||
|
||||
if (_type == Type::FLOAT) {
|
||||
return static_cast<unsigned char>(_field.floatVal);
|
||||
}
|
||||
|
||||
if (_type == Type::DOUBLE) {
|
||||
return static_cast<unsigned char>(_field.doubleVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Value::asInt() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
if (_type == Type::INTEGER) {
|
||||
return _field.intVal;
|
||||
}
|
||||
|
||||
if (_type == Type::UNSIGNED) {
|
||||
CC_ASSERT(_field.unsignedVal < INT_MAX);
|
||||
return static_cast<int>(_field.unsignedVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return _field.byteVal;
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return atoi(_field.strVal->c_str());
|
||||
}
|
||||
|
||||
if (_type == Type::FLOAT) {
|
||||
return static_cast<int>(_field.floatVal);
|
||||
}
|
||||
|
||||
if (_type == Type::DOUBLE) {
|
||||
return static_cast<int>(_field.doubleVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int Value::asUnsignedInt() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
if (_type == Type::UNSIGNED) {
|
||||
return _field.unsignedVal;
|
||||
}
|
||||
|
||||
if (_type == Type::INTEGER) {
|
||||
CC_ASSERT(_field.intVal >= 0);
|
||||
return static_cast<unsigned int>(_field.intVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return static_cast<unsigned int>(_field.byteVal);
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
// NOTE: strtoul is required (need to augment on unsupported platforms)
|
||||
return static_cast<unsigned int>(strtoul(_field.strVal->c_str(), nullptr, 10));
|
||||
}
|
||||
|
||||
if (_type == Type::FLOAT) {
|
||||
return static_cast<unsigned int>(_field.floatVal);
|
||||
}
|
||||
|
||||
if (_type == Type::DOUBLE) {
|
||||
return static_cast<unsigned int>(_field.doubleVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal ? 1U : 0U;
|
||||
}
|
||||
|
||||
return 0U;
|
||||
}
|
||||
|
||||
float Value::asFloat() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
if (_type == Type::FLOAT) {
|
||||
return _field.floatVal;
|
||||
}
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return static_cast<float>(_field.byteVal);
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return static_cast<float>(utils::atof(_field.strVal->c_str()));
|
||||
}
|
||||
|
||||
if (_type == Type::INTEGER) {
|
||||
return static_cast<float>(_field.intVal);
|
||||
}
|
||||
|
||||
if (_type == Type::UNSIGNED) {
|
||||
return static_cast<float>(_field.unsignedVal);
|
||||
}
|
||||
|
||||
if (_type == Type::DOUBLE) {
|
||||
return static_cast<float>(_field.doubleVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal ? 1.0F : 0.0F;
|
||||
}
|
||||
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
double Value::asDouble() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
if (_type == Type::DOUBLE) {
|
||||
return _field.doubleVal;
|
||||
}
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return static_cast<double>(_field.byteVal);
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return static_cast<double>(utils::atof(_field.strVal->c_str()));
|
||||
}
|
||||
|
||||
if (_type == Type::INTEGER) {
|
||||
return static_cast<double>(_field.intVal);
|
||||
}
|
||||
|
||||
if (_type == Type::UNSIGNED) {
|
||||
return static_cast<double>(_field.unsignedVal);
|
||||
}
|
||||
|
||||
if (_type == Type::FLOAT) {
|
||||
return static_cast<double>(_field.floatVal);
|
||||
}
|
||||
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal ? 1.0 : 0.0;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool Value::asBool() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
if (_type == Type::BOOLEAN) {
|
||||
return _field.boolVal;
|
||||
}
|
||||
|
||||
if (_type == Type::BYTE) {
|
||||
return _field.byteVal != 0;
|
||||
}
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return *_field.strVal != "0" || *_field.strVal != "false";
|
||||
}
|
||||
|
||||
if (_type == Type::INTEGER) {
|
||||
return _field.intVal != 0;
|
||||
}
|
||||
|
||||
if (_type == Type::UNSIGNED) {
|
||||
return _field.unsignedVal != 0;
|
||||
}
|
||||
|
||||
if (_type == Type::FLOAT) {
|
||||
return _field.floatVal != 0.0F;
|
||||
}
|
||||
|
||||
if (_type == Type::DOUBLE) {
|
||||
return _field.doubleVal != 0.0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ccstd::string Value::asString() const {
|
||||
CC_ASSERT(_type != Type::VECTOR && _type != Type::MAP && _type != Type::INT_KEY_MAP);
|
||||
|
||||
if (_type == Type::STRING) {
|
||||
return *_field.strVal;
|
||||
}
|
||||
|
||||
std::stringstream ret;
|
||||
|
||||
switch (_type) {
|
||||
case Type::BYTE:
|
||||
ret << _field.byteVal;
|
||||
break;
|
||||
case Type::INTEGER:
|
||||
ret << _field.intVal;
|
||||
break;
|
||||
case Type::UNSIGNED:
|
||||
ret << _field.unsignedVal;
|
||||
break;
|
||||
case Type::FLOAT:
|
||||
ret << std::fixed << std::setprecision(7) << _field.floatVal;
|
||||
break;
|
||||
case Type::DOUBLE:
|
||||
ret << std::fixed << std::setprecision(16) << _field.doubleVal;
|
||||
break;
|
||||
case Type::BOOLEAN:
|
||||
ret << (_field.boolVal ? "true" : "false");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
ValueVector &Value::asValueVector() {
|
||||
CC_ASSERT_EQ(_type, Type::VECTOR);
|
||||
return *_field.vectorVal;
|
||||
}
|
||||
|
||||
const ValueVector &Value::asValueVector() const {
|
||||
CC_ASSERT_EQ(_type, Type::VECTOR);
|
||||
return *_field.vectorVal;
|
||||
}
|
||||
|
||||
ValueMap &Value::asValueMap() {
|
||||
CC_ASSERT_EQ(_type, Type::MAP);
|
||||
return *_field.mapVal;
|
||||
}
|
||||
|
||||
const ValueMap &Value::asValueMap() const {
|
||||
CC_ASSERT_EQ(_type, Type::MAP);
|
||||
return *_field.mapVal;
|
||||
}
|
||||
|
||||
ValueMapIntKey &Value::asIntKeyMap() {
|
||||
CC_ASSERT_EQ(_type, Type::INT_KEY_MAP);
|
||||
return *_field.intKeyMapVal;
|
||||
}
|
||||
|
||||
const ValueMapIntKey &Value::asIntKeyMap() const {
|
||||
CC_ASSERT_EQ(_type, Type::INT_KEY_MAP);
|
||||
return *_field.intKeyMapVal;
|
||||
}
|
||||
|
||||
static ccstd::string getTabs(int depth) {
|
||||
ccstd::string tabWidth;
|
||||
|
||||
for (int i = 0; i < depth; ++i) {
|
||||
tabWidth += "\t";
|
||||
}
|
||||
|
||||
return tabWidth;
|
||||
}
|
||||
|
||||
static ccstd::string visit(const Value &v, int depth);
|
||||
|
||||
static ccstd::string visitVector(const ValueVector &v, int depth) { //NOLINT[misc-no-recursion]
|
||||
std::stringstream ret;
|
||||
|
||||
if (depth > 0) {
|
||||
ret << "\n";
|
||||
}
|
||||
|
||||
ret << getTabs(depth) << "[\n";
|
||||
|
||||
int i = 0;
|
||||
for (const auto &child : v) {
|
||||
ret << getTabs(depth + 1) << i << ": " << visit(child, depth + 1);
|
||||
++i;
|
||||
}
|
||||
|
||||
ret << getTabs(depth) << "]\n";
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static ccstd::string visitMap(const T &v, int depth) { //NOLINT[misc-no-recursion]
|
||||
std::stringstream ret;
|
||||
|
||||
if (depth > 0) {
|
||||
ret << "\n";
|
||||
}
|
||||
|
||||
ret << getTabs(depth) << "{\n";
|
||||
|
||||
for (auto iter = v.begin(); iter != v.end(); ++iter) {
|
||||
ret << getTabs(depth + 1) << iter->first << ": ";
|
||||
ret << visit(iter->second, depth + 1);
|
||||
}
|
||||
|
||||
ret << getTabs(depth) << "}\n";
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
static ccstd::string visit(const Value &v, int depth) { //NOLINT[misc-no-recursion]
|
||||
std::stringstream ret;
|
||||
|
||||
switch (v.getType()) {
|
||||
case Value::Type::NONE:
|
||||
case Value::Type::BYTE:
|
||||
case Value::Type::INTEGER:
|
||||
case Value::Type::UNSIGNED:
|
||||
case Value::Type::FLOAT:
|
||||
case Value::Type::DOUBLE:
|
||||
case Value::Type::BOOLEAN:
|
||||
case Value::Type::STRING:
|
||||
ret << v.asString() << "\n";
|
||||
break;
|
||||
case Value::Type::VECTOR:
|
||||
ret << visitVector(v.asValueVector(), depth);
|
||||
break;
|
||||
case Value::Type::MAP:
|
||||
ret << visitMap(v.asValueMap(), depth);
|
||||
break;
|
||||
case Value::Type::INT_KEY_MAP:
|
||||
ret << visitMap(v.asIntKeyMap(), depth);
|
||||
break;
|
||||
default:
|
||||
CC_ABORT();
|
||||
break;
|
||||
}
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
ccstd::string Value::getDescription() const {
|
||||
ccstd::string ret("\n");
|
||||
ret += visit(*this, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Value::clear() {
|
||||
// Free memory the old value allocated
|
||||
switch (_type) {
|
||||
case Type::BYTE:
|
||||
_field.byteVal = 0;
|
||||
break;
|
||||
case Type::INTEGER:
|
||||
_field.intVal = 0;
|
||||
break;
|
||||
case Type::UNSIGNED:
|
||||
_field.unsignedVal = 0U;
|
||||
break;
|
||||
case Type::FLOAT:
|
||||
_field.floatVal = 0.0F;
|
||||
break;
|
||||
case Type::DOUBLE:
|
||||
_field.doubleVal = 0.0;
|
||||
break;
|
||||
case Type::BOOLEAN:
|
||||
_field.boolVal = false;
|
||||
break;
|
||||
case Type::STRING:
|
||||
CC_SAFE_DELETE(_field.strVal);
|
||||
break;
|
||||
case Type::VECTOR:
|
||||
CC_SAFE_DELETE(_field.vectorVal);
|
||||
break;
|
||||
case Type::MAP:
|
||||
CC_SAFE_DELETE(_field.mapVal);
|
||||
break;
|
||||
case Type::INT_KEY_MAP:
|
||||
CC_SAFE_DELETE(_field.intKeyMapVal);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_type = Type::NONE;
|
||||
}
|
||||
|
||||
void Value::reset(Type type) {
|
||||
if (_type == type) {
|
||||
return;
|
||||
}
|
||||
|
||||
clear();
|
||||
|
||||
// Allocate memory for the new value
|
||||
switch (type) {
|
||||
case Type::STRING:
|
||||
_field.strVal = ccnew ccstd::string();
|
||||
break;
|
||||
case Type::VECTOR:
|
||||
_field.vectorVal = ccnew ValueVector();
|
||||
break;
|
||||
case Type::MAP:
|
||||
_field.mapVal = ccnew ValueMap();
|
||||
break;
|
||||
case Type::INT_KEY_MAP:
|
||||
_field.intKeyMapVal = ccnew ValueMapIntKey();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_type = type;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
238
cocos/base/Value.h
Normal file
238
cocos/base/Value.h
Normal file
@@ -0,0 +1,238 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class Value;
|
||||
|
||||
using ValueVector = ccstd::vector<Value>;
|
||||
using ValueMap = ccstd::unordered_map<ccstd::string, Value>;
|
||||
using ValueMapIntKey = ccstd::unordered_map<int, Value>;
|
||||
|
||||
CC_DLL extern const ValueVector VALUE_VECTOR_NULL;
|
||||
CC_DLL extern const ValueMap VALUE_MAP_NULL;
|
||||
CC_DLL extern const ValueMapIntKey VALUE_MAP_INT_KEY_NULL;
|
||||
|
||||
/*
|
||||
* This class is provide as a wrapper of basic types, such as int and bool.
|
||||
*/
|
||||
class CC_DLL Value {
|
||||
public:
|
||||
/** A predefined Value that has not value. */
|
||||
static const Value VALUE_NULL;
|
||||
|
||||
/** Default constructor. */
|
||||
Value();
|
||||
|
||||
/** Create a Value by an unsigned char value. */
|
||||
explicit Value(unsigned char v);
|
||||
|
||||
/** Create a Value by an integer value. */
|
||||
explicit Value(int v);
|
||||
|
||||
/** Create a Value by an unsigned value. */
|
||||
explicit Value(unsigned int v);
|
||||
|
||||
/** Create a Value by a float value. */
|
||||
explicit Value(float v);
|
||||
|
||||
/** Create a Value by a double value. */
|
||||
explicit Value(double v);
|
||||
|
||||
/** Create a Value by a bool value. */
|
||||
explicit Value(bool v);
|
||||
|
||||
/** Create a Value by a char pointer. It will copy the chars internally. */
|
||||
explicit Value(const char *v);
|
||||
|
||||
/** Create a Value by a string. */
|
||||
explicit Value(const ccstd::string &v);
|
||||
|
||||
/** Create a Value by a ValueVector object. */
|
||||
explicit Value(const ValueVector &v);
|
||||
/** Create a Value by a ValueVector object. It will use std::move internally. */
|
||||
explicit Value(ValueVector &&v);
|
||||
|
||||
/** Create a Value by a ValueMap object. */
|
||||
explicit Value(const ValueMap &v);
|
||||
/** Create a Value by a ValueMap object. It will use std::move internally. */
|
||||
explicit Value(ValueMap &&v);
|
||||
|
||||
/** Create a Value by a ValueMapIntKey object. */
|
||||
explicit Value(const ValueMapIntKey &v);
|
||||
/** Create a Value by a ValueMapIntKey object. It will use std::move internally. */
|
||||
explicit Value(ValueMapIntKey &&v);
|
||||
|
||||
/** Create a Value by another Value object. */
|
||||
Value(const Value &other);
|
||||
/** Create a Value by a Value object. It will use std::move internally. */
|
||||
Value(Value &&other) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~Value();
|
||||
|
||||
/** Assignment operator, assign from Value to Value. */
|
||||
Value &operator=(const Value &other);
|
||||
/** Assignment operator, assign from Value to Value. It will use std::move internally. */
|
||||
Value &operator=(Value &&other) noexcept;
|
||||
|
||||
/** Assignment operator, assign from unsigned char to Value. */
|
||||
Value &operator=(unsigned char v);
|
||||
/** Assignment operator, assign from integer to Value. */
|
||||
Value &operator=(int v);
|
||||
/** Assignment operator, assign from integer to Value. */
|
||||
Value &operator=(unsigned int v);
|
||||
/** Assignment operator, assign from float to Value. */
|
||||
Value &operator=(float v);
|
||||
/** Assignment operator, assign from double to Value. */
|
||||
Value &operator=(double v);
|
||||
/** Assignment operator, assign from bool to Value. */
|
||||
Value &operator=(bool v);
|
||||
/** Assignment operator, assign from char* to Value. */
|
||||
Value &operator=(const char *v);
|
||||
/** Assignment operator, assign from string to Value. */
|
||||
Value &operator=(const ccstd::string &v);
|
||||
|
||||
/** Assignment operator, assign from ValueVector to Value. */
|
||||
Value &operator=(const ValueVector &v);
|
||||
/** Assignment operator, assign from ValueVector to Value. */
|
||||
Value &operator=(ValueVector &&v);
|
||||
|
||||
/** Assignment operator, assign from ValueMap to Value. */
|
||||
Value &operator=(const ValueMap &v);
|
||||
/** Assignment operator, assign from ValueMap to Value. It will use std::move internally. */
|
||||
Value &operator=(ValueMap &&v);
|
||||
|
||||
/** Assignment operator, assign from ValueMapIntKey to Value. */
|
||||
Value &operator=(const ValueMapIntKey &v);
|
||||
/** Assignment operator, assign from ValueMapIntKey to Value. It will use std::move internally. */
|
||||
Value &operator=(ValueMapIntKey &&v);
|
||||
|
||||
/** != operator overloading */
|
||||
bool operator!=(const Value &v);
|
||||
/** != operator overloading */
|
||||
bool operator!=(const Value &v) const;
|
||||
/** == operator overloading */
|
||||
bool operator==(const Value &v);
|
||||
/** == operator overloading */
|
||||
bool operator==(const Value &v) const;
|
||||
|
||||
/** Gets as a byte value. Will convert to unsigned char if possible, or will trigger assert error. */
|
||||
unsigned char asByte() const;
|
||||
/** Gets as an integer value. Will convert to integer if possible, or will trigger assert error. */
|
||||
int asInt() const;
|
||||
/** Gets as an unsigned value. Will convert to unsigned if possible, or will trigger assert error. */
|
||||
unsigned int asUnsignedInt() const;
|
||||
/** Gets as a float value. Will convert to float if possible, or will trigger assert error. */
|
||||
float asFloat() const;
|
||||
/** Gets as a double value. Will convert to double if possible, or will trigger assert error. */
|
||||
double asDouble() const;
|
||||
/** Gets as a bool value. Will convert to bool if possible, or will trigger assert error. */
|
||||
bool asBool() const;
|
||||
/** Gets as a string value. Will convert to string if possible, or will trigger assert error. */
|
||||
ccstd::string asString() const;
|
||||
|
||||
/** Gets as a ValueVector reference. Will convert to ValueVector if possible, or will trigger assert error. */
|
||||
ValueVector &asValueVector();
|
||||
/** Gets as a const ValueVector reference. Will convert to ValueVector if possible, or will trigger assert error. */
|
||||
const ValueVector &asValueVector() const;
|
||||
|
||||
/** Gets as a ValueMap reference. Will convert to ValueMap if possible, or will trigger assert error. */
|
||||
ValueMap &asValueMap();
|
||||
/** Gets as a const ValueMap reference. Will convert to ValueMap if possible, or will trigger assert error. */
|
||||
const ValueMap &asValueMap() const;
|
||||
|
||||
/** Gets as a ValueMapIntKey reference. Will convert to ValueMapIntKey if possible, or will trigger assert error. */
|
||||
ValueMapIntKey &asIntKeyMap();
|
||||
/** Gets as a const ValueMapIntKey reference. Will convert to ValueMapIntKey if possible, or will trigger assert error. */
|
||||
const ValueMapIntKey &asIntKeyMap() const;
|
||||
|
||||
/**
|
||||
* Checks if the Value is null.
|
||||
* @return True if the Value is null, false if not.
|
||||
*/
|
||||
inline bool isNull() const { return _type == Type::NONE; }
|
||||
|
||||
/** Value type wrapped by Value. */
|
||||
enum class Type {
|
||||
/// no value is wrapped, an empty Value
|
||||
NONE = 0,
|
||||
/// wrap byte
|
||||
BYTE,
|
||||
/// wrap integer
|
||||
INTEGER,
|
||||
/// wrap unsigned
|
||||
UNSIGNED,
|
||||
/// wrap float
|
||||
FLOAT,
|
||||
/// wrap double
|
||||
DOUBLE,
|
||||
/// wrap bool
|
||||
BOOLEAN,
|
||||
/// wrap string
|
||||
STRING,
|
||||
/// wrap vector
|
||||
VECTOR,
|
||||
/// wrap ValueMap
|
||||
MAP,
|
||||
/// wrap ValueMapIntKey
|
||||
INT_KEY_MAP
|
||||
};
|
||||
|
||||
/** Gets the value type. */
|
||||
inline Type getType() const { return _type; }
|
||||
|
||||
/** Gets the description of the class. */
|
||||
ccstd::string getDescription() const;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void reset(Type type);
|
||||
|
||||
union {
|
||||
unsigned char byteVal;
|
||||
int intVal;
|
||||
unsigned int unsignedVal;
|
||||
float floatVal;
|
||||
double doubleVal;
|
||||
bool boolVal;
|
||||
|
||||
ccstd::string *strVal;
|
||||
ValueVector *vectorVal;
|
||||
ValueMap *mapVal;
|
||||
ValueMapIntKey *intKeyMapVal;
|
||||
} _field;
|
||||
|
||||
Type _type;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
657
cocos/base/ZipUtils.cpp
Normal file
657
cocos/base/ZipUtils.cpp
Normal file
@@ -0,0 +1,657 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// IDEA: hack, must be included before ziputils
|
||||
#include "base/ZipUtils.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#ifdef MINIZIP_FROM_SYSTEM
|
||||
#include <minizip/unzip.h>
|
||||
#else // from our embedded sources
|
||||
#include "unzip/unzip.h"
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include "base/Data.h"
|
||||
#include "base/Locked.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "platform/FileUtils.h"
|
||||
#include "unzip/ioapi_mem.h"
|
||||
|
||||
// minizip 1.2.0 is same with other platforms
|
||||
#ifndef unzGoToFirstFile64
|
||||
#define unzGoToFirstFile64(A, B, C, D) unzGoToFirstFile2(A, B, C, D, NULL, 0, NULL, 0) // NOLINT(readability-identifier-naming)
|
||||
#define unzGoToNextFile64(A, B, C, D) unzGoToNextFile2(A, B, C, D, NULL, 0, NULL, 0) // NOLINT(readability-identifier-naming)#endif
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
unsigned int ZipUtils::encryptedPvrKeyParts[4] = {0, 0, 0, 0};
|
||||
unsigned int ZipUtils::encryptionKey[1024];
|
||||
bool ZipUtils::encryptionKeyIsValid = false;
|
||||
|
||||
// --------------------- ZipUtils ---------------------
|
||||
|
||||
inline void ZipUtils::decodeEncodedPvr(unsigned int *data, uint32_t len) {
|
||||
const int enclen = 1024;
|
||||
const int securelen = 512;
|
||||
const int distance = 64;
|
||||
|
||||
// check if key was set
|
||||
// make sure to call caw_setkey_part() for all 4 key parts
|
||||
CC_ASSERT(ZipUtils::encryptedPvrKeyParts[0] != 0); // CCZ file is encrypted but key part 0 is not set. Call ZipUtils::setPvrEncryptionKeyPart(...)?
|
||||
CC_ASSERT(ZipUtils::encryptedPvrKeyParts[1] != 0); // CCZ file is encrypted but key part 1 is not set. Call ZipUtils::setPvrEncryptionKeyPart(...)?
|
||||
CC_ASSERT(ZipUtils::encryptedPvrKeyParts[2] != 0); // CCZ file is encrypted but key part 2 is not set. Call ZipUtils::setPvrEncryptionKeyPart(...)?
|
||||
CC_ASSERT(ZipUtils::encryptedPvrKeyParts[3] != 0); // CCZ file is encrypted but key part 3 is not set. Call ZipUtils::setPvrEncryptionKeyPart(...)?
|
||||
|
||||
// create long key
|
||||
if (!ZipUtils::encryptionKeyIsValid) {
|
||||
unsigned int y{0};
|
||||
unsigned int p{0};
|
||||
unsigned int e{0};
|
||||
unsigned int rounds = 6;
|
||||
unsigned int sum = 0;
|
||||
unsigned int z = ZipUtils::encryptionKey[enclen - 1];
|
||||
|
||||
do {
|
||||
#define DELTA 0x9e3779b9
|
||||
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (ZipUtils::encryptedPvrKeyParts[(p & 3) ^ e] ^ z)))
|
||||
|
||||
sum += DELTA;
|
||||
e = (sum >> 2) & 3;
|
||||
|
||||
for (p = 0; p < enclen - 1; p++) {
|
||||
y = ZipUtils::encryptionKey[p + 1];
|
||||
z = ZipUtils::encryptionKey[p] += MX;
|
||||
}
|
||||
|
||||
y = ZipUtils::encryptionKey[0];
|
||||
z = ZipUtils::encryptionKey[enclen - 1] += MX;
|
||||
|
||||
} while (--rounds);
|
||||
|
||||
ZipUtils::encryptionKeyIsValid = true;
|
||||
}
|
||||
|
||||
int b = 0;
|
||||
int i = 0;
|
||||
|
||||
// encrypt first part completely
|
||||
for (; i < len && i < securelen; i++) {
|
||||
data[i] ^= ZipUtils::encryptionKey[b++];
|
||||
|
||||
if (b >= enclen) {
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// encrypt second section partially
|
||||
for (; i < len; i += distance) {
|
||||
data[i] ^= ZipUtils::encryptionKey[b++];
|
||||
|
||||
if (b >= enclen) {
|
||||
b = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned int ZipUtils::checksumPvr(const unsigned int *data, uint32_t len) {
|
||||
unsigned int cs = 0;
|
||||
const int cslen = 128;
|
||||
|
||||
len = (len < cslen) ? len : cslen;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
cs = cs ^ data[i];
|
||||
}
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
// memory in iPhone is precious
|
||||
// Should buffer factor be 1.5 instead of 2 ?
|
||||
#define BUFFER_INC_FACTOR (2)
|
||||
|
||||
int ZipUtils::inflateMemoryWithHint(unsigned char *in, uint32_t inLength, unsigned char **out, uint32_t *outLength, uint32_t outLengthHint) {
|
||||
/* ret value */
|
||||
int err = Z_OK;
|
||||
uint32_t bufferSize = outLengthHint;
|
||||
*out = static_cast<unsigned char *>(malloc(bufferSize));
|
||||
|
||||
z_stream descompressionStream; /* decompression stream */
|
||||
descompressionStream.zalloc = static_cast<alloc_func>(nullptr);
|
||||
descompressionStream.zfree = static_cast<free_func>(nullptr);
|
||||
descompressionStream.opaque = static_cast<voidpf>(nullptr);
|
||||
|
||||
descompressionStream.next_in = in;
|
||||
descompressionStream.avail_in = inLength;
|
||||
descompressionStream.next_out = *out;
|
||||
descompressionStream.avail_out = bufferSize;
|
||||
|
||||
/* window size to hold 256k */
|
||||
if ((err = inflateInit2(&descompressionStream, 15 + 32)) != Z_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
err = inflate(&descompressionStream, Z_NO_FLUSH);
|
||||
|
||||
if (err == Z_STREAM_END) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (err) {
|
||||
case Z_NEED_DICT:
|
||||
err = Z_DATA_ERROR;
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&descompressionStream);
|
||||
return err;
|
||||
}
|
||||
|
||||
// not enough memory ?
|
||||
if (err != Z_STREAM_END) {
|
||||
*out = static_cast<unsigned char *>(realloc(*out, bufferSize * BUFFER_INC_FACTOR));
|
||||
|
||||
/* not enough memory, ouch */
|
||||
if (!*out) {
|
||||
CC_LOG_DEBUG("ZipUtils: realloc failed");
|
||||
inflateEnd(&descompressionStream);
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
|
||||
descompressionStream.next_out = *out + bufferSize;
|
||||
descompressionStream.avail_out = static_cast<unsigned int>(bufferSize);
|
||||
bufferSize *= BUFFER_INC_FACTOR;
|
||||
}
|
||||
}
|
||||
|
||||
*outLength = bufferSize - descompressionStream.avail_out;
|
||||
err = inflateEnd(&descompressionStream);
|
||||
return err;
|
||||
}
|
||||
|
||||
uint32_t ZipUtils::inflateMemoryWithHint(unsigned char *in, uint32_t inLength, unsigned char **out, uint32_t outLengthHint) {
|
||||
uint32_t outLength = 0;
|
||||
int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint);
|
||||
|
||||
if (err != Z_OK || *out == nullptr) {
|
||||
if (err == Z_MEM_ERROR) {
|
||||
CC_LOG_DEBUG("ZipUtils: Out of memory while decompressing map data!");
|
||||
} else if (err == Z_VERSION_ERROR) {
|
||||
CC_LOG_DEBUG("ZipUtils: Incompatible zlib version!");
|
||||
} else if (err == Z_DATA_ERROR) {
|
||||
CC_LOG_DEBUG("ZipUtils: Incorrect zlib compressed data!");
|
||||
} else {
|
||||
CC_LOG_DEBUG("ZipUtils: Unknown error while decompressing map data!");
|
||||
}
|
||||
|
||||
if (*out) {
|
||||
free(*out);
|
||||
*out = nullptr;
|
||||
}
|
||||
outLength = 0;
|
||||
}
|
||||
|
||||
return outLength;
|
||||
}
|
||||
|
||||
uint32_t ZipUtils::inflateMemory(unsigned char *in, uint32_t inLength, unsigned char **out) {
|
||||
// 256k for hint
|
||||
return inflateMemoryWithHint(in, inLength, out, 256 * 1024);
|
||||
}
|
||||
|
||||
int ZipUtils::inflateGZipFile(const char *path, unsigned char **out) {
|
||||
int len;
|
||||
int offset = 0;
|
||||
|
||||
CC_ASSERT(out);
|
||||
CC_ASSERT(&*out);
|
||||
|
||||
gzFile inFile = gzopen(FileUtils::getInstance()->getSuitableFOpen(path).c_str(), "rb");
|
||||
if (inFile == nullptr) {
|
||||
CC_LOG_DEBUG("ZipUtils: error open gzip file: %s", path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 512k initial decompress buffer */
|
||||
unsigned int bufferSize = 512 * 1024;
|
||||
unsigned int totalBufferSize = bufferSize;
|
||||
|
||||
*out = static_cast<unsigned char *>(malloc(bufferSize));
|
||||
if (!out) {
|
||||
CC_LOG_DEBUG("ZipUtils: out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
len = gzread(inFile, *out + offset, bufferSize);
|
||||
if (len < 0) {
|
||||
CC_LOG_DEBUG("ZipUtils: error in gzread");
|
||||
free(*out);
|
||||
*out = nullptr;
|
||||
return -1;
|
||||
}
|
||||
if (len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
|
||||
// finish reading the file
|
||||
if (static_cast<unsigned int>(len) < bufferSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
bufferSize *= BUFFER_INC_FACTOR;
|
||||
totalBufferSize += bufferSize;
|
||||
auto *tmp = static_cast<unsigned char *>(realloc(*out, totalBufferSize));
|
||||
|
||||
if (!tmp) {
|
||||
CC_LOG_DEBUG("ZipUtils: out of memory");
|
||||
free(*out);
|
||||
*out = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = tmp;
|
||||
}
|
||||
|
||||
if (gzclose(inFile) != Z_OK) {
|
||||
CC_LOG_DEBUG("ZipUtils: gzclose failed");
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool ZipUtils::isCCZFile(const char *path) {
|
||||
// load file into memory
|
||||
Data compressedData = FileUtils::getInstance()->getDataFromFile(path);
|
||||
|
||||
if (compressedData.isNull()) {
|
||||
CC_LOG_DEBUG("ZipUtils: loading file failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return isCCZBuffer(compressedData.getBytes(), compressedData.getSize());
|
||||
}
|
||||
|
||||
bool ZipUtils::isCCZBuffer(const unsigned char *buffer, uint32_t len) {
|
||||
if (len < sizeof(struct CCZHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto *header = reinterpret_cast<const struct CCZHeader *>(buffer);
|
||||
return header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && (header->sig[3] == '!' || header->sig[3] == 'p');
|
||||
}
|
||||
|
||||
bool ZipUtils::isGZipFile(const char *path) {
|
||||
// load file into memory
|
||||
Data compressedData = FileUtils::getInstance()->getDataFromFile(path);
|
||||
|
||||
if (compressedData.isNull()) {
|
||||
CC_LOG_DEBUG("ZipUtils: loading file failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return isGZipBuffer(compressedData.getBytes(), compressedData.getSize());
|
||||
}
|
||||
|
||||
bool ZipUtils::isGZipBuffer(const unsigned char *buffer, uint32_t len) {
|
||||
if (len < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return buffer[0] == 0x1F && buffer[1] == 0x8B;
|
||||
}
|
||||
|
||||
int ZipUtils::inflateCCZBuffer(const unsigned char *buffer, uint32_t bufferLen, unsigned char **out) {
|
||||
const auto *header = reinterpret_cast<const struct CCZHeader *>(buffer);
|
||||
|
||||
// verify header
|
||||
if (header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == '!') {
|
||||
// verify header version
|
||||
unsigned int version = CC_SWAP_INT16_BIG_TO_HOST(header->version);
|
||||
if (version > 2) {
|
||||
CC_LOG_DEBUG("Unsupported CCZ header format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// verify compression format
|
||||
if (CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB) {
|
||||
CC_LOG_DEBUG("CCZ Unsupported compression method");
|
||||
return -1;
|
||||
}
|
||||
} else if (header->sig[0] == 'C' && header->sig[1] == 'C' && header->sig[2] == 'Z' && header->sig[3] == 'p') {
|
||||
// encrypted ccz file
|
||||
header = reinterpret_cast<const struct CCZHeader *>(buffer);
|
||||
|
||||
// verify header version
|
||||
unsigned int version = CC_SWAP_INT16_BIG_TO_HOST(header->version);
|
||||
if (version > 0) {
|
||||
CC_LOG_DEBUG("Unsupported CCZ header format");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// verify compression format
|
||||
if (CC_SWAP_INT16_BIG_TO_HOST(header->compression_type) != CCZ_COMPRESSION_ZLIB) {
|
||||
CC_LOG_DEBUG("CCZ Unsupported compression method");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if CC_DEBUG > 0
|
||||
// decrypt
|
||||
auto *ints = reinterpret_cast<unsigned int *>(const_cast<unsigned char *>(buffer) + 12);
|
||||
uint32_t enclen = (bufferLen - 12) / 4;
|
||||
|
||||
decodeEncodedPvr(ints, enclen);
|
||||
// verify checksum in debug mode
|
||||
unsigned int calculated = checksumPvr(ints, enclen);
|
||||
unsigned int required = CC_SWAP_INT32_BIG_TO_HOST(header->reserved);
|
||||
|
||||
if (calculated != required) {
|
||||
CC_LOG_DEBUG("Can't decrypt image file. Is the decryption key valid?");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
CC_LOG_DEBUG("Invalid CCZ file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int len = CC_SWAP_INT32_BIG_TO_HOST(header->len);
|
||||
|
||||
*out = static_cast<unsigned char *>(malloc(len));
|
||||
if (!*out) {
|
||||
CC_LOG_DEBUG("CCZ: Failed to allocate memory for texture");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uLongf destlen = len;
|
||||
const auto *source = reinterpret_cast<const Bytef *>(buffer + sizeof(*header));
|
||||
int ret = uncompress(*out, &destlen, source, static_cast<uLong>(bufferLen - sizeof(*header)));
|
||||
|
||||
if (ret != Z_OK) {
|
||||
CC_LOG_DEBUG("CCZ: Failed to uncompress data");
|
||||
free(*out);
|
||||
*out = nullptr;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int>(len);
|
||||
}
|
||||
|
||||
int ZipUtils::inflateCCZFile(const char *path, unsigned char **out) {
|
||||
CC_ASSERT(out);
|
||||
|
||||
// load file into memory
|
||||
Data compressedData = FileUtils::getInstance()->getDataFromFile(path);
|
||||
|
||||
if (compressedData.isNull()) {
|
||||
CC_LOG_DEBUG("Error loading CCZ compressed file");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return inflateCCZBuffer(compressedData.getBytes(), compressedData.getSize(), out);
|
||||
}
|
||||
|
||||
void ZipUtils::setPvrEncryptionKeyPart(int index, unsigned int value) {
|
||||
CC_ASSERT_GE(index, 0);
|
||||
CC_ASSERT_LE(index, 3);
|
||||
|
||||
if (ZipUtils::encryptedPvrKeyParts[index] != value) {
|
||||
ZipUtils::encryptedPvrKeyParts[index] = value;
|
||||
ZipUtils::encryptionKeyIsValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipUtils::setPvrEncryptionKey(unsigned int keyPart1, unsigned int keyPart2, unsigned int keyPart3, unsigned int keyPart4) {
|
||||
setPvrEncryptionKeyPart(0, keyPart1);
|
||||
setPvrEncryptionKeyPart(1, keyPart2);
|
||||
setPvrEncryptionKeyPart(2, keyPart3);
|
||||
setPvrEncryptionKeyPart(3, keyPart4);
|
||||
}
|
||||
|
||||
// --------------------- ZipFile ---------------------
|
||||
// from unzip.cpp
|
||||
#define UNZ_MAXFILENAMEINZIP 256
|
||||
|
||||
static const ccstd::string EMPTY_FILE_NAME;
|
||||
|
||||
struct ZipEntryInfo {
|
||||
unz_file_pos pos;
|
||||
uLong uncompressed_size;
|
||||
};
|
||||
|
||||
class ZipFilePrivate {
|
||||
public:
|
||||
Locked<unzFile, std::recursive_mutex> zipFile;
|
||||
std::unique_ptr<ourmemory_s> memfs;
|
||||
|
||||
// ccstd::unordered_map is faster if available on the platform
|
||||
using FileListContainer = ccstd::unordered_map<ccstd::string, struct ZipEntryInfo>;
|
||||
FileListContainer fileList;
|
||||
};
|
||||
|
||||
ZipFile *ZipFile::createWithBuffer(const void *buffer, uint32_t size) {
|
||||
auto *zip = ccnew ZipFile();
|
||||
if (zip && zip->initWithBuffer(buffer, size)) {
|
||||
return zip;
|
||||
}
|
||||
delete zip;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZipFile::ZipFile()
|
||||
: _data(ccnew ZipFilePrivate) {
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
*zipFile = nullptr;
|
||||
}
|
||||
|
||||
ZipFile::ZipFile(const ccstd::string &zipFile, const ccstd::string &filter)
|
||||
: _data(ccnew ZipFilePrivate) {
|
||||
auto zipFileL = _data->zipFile.lock();
|
||||
*zipFileL = unzOpen(FileUtils::getInstance()->getSuitableFOpen(zipFile).c_str());
|
||||
setFilter(filter);
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile() {
|
||||
if (_data) {
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
if (*zipFile) {
|
||||
unzClose(*zipFile);
|
||||
}
|
||||
}
|
||||
|
||||
CC_SAFE_DELETE(_data);
|
||||
}
|
||||
|
||||
bool ZipFile::setFilter(const ccstd::string &filter) {
|
||||
bool ret = false;
|
||||
do {
|
||||
CC_BREAK_IF(!_data);
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
CC_BREAK_IF(!(*zipFile));
|
||||
|
||||
// clear existing file list
|
||||
_data->fileList.clear();
|
||||
|
||||
// UNZ_MAXFILENAMEINZIP + 1 - it is done so in unzLocateFile
|
||||
char szCurrentFileName[UNZ_MAXFILENAMEINZIP + 1];
|
||||
unz_file_info64 fileInfo;
|
||||
|
||||
// go through all files and store position information about the required files
|
||||
int err = unzGoToFirstFile64(*zipFile, &fileInfo,
|
||||
szCurrentFileName, sizeof(szCurrentFileName) - 1);
|
||||
while (err == UNZ_OK) {
|
||||
unz_file_pos posInfo;
|
||||
int posErr = unzGetFilePos(*zipFile, &posInfo);
|
||||
if (posErr == UNZ_OK) {
|
||||
ccstd::string currentFileName = szCurrentFileName;
|
||||
// cache info about filtered files only (like 'assets/')
|
||||
if (filter.empty() || currentFileName.substr(0, filter.length()) == filter) {
|
||||
ZipEntryInfo entry;
|
||||
entry.pos = posInfo;
|
||||
entry.uncompressed_size = static_cast<uLong>(fileInfo.uncompressed_size);
|
||||
_data->fileList[currentFileName] = entry;
|
||||
}
|
||||
}
|
||||
// next file - also get the information about it
|
||||
err = unzGoToNextFile64(*zipFile, &fileInfo,
|
||||
szCurrentFileName, sizeof(szCurrentFileName) - 1);
|
||||
}
|
||||
ret = true;
|
||||
|
||||
} while (false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ZipFile::fileExists(const ccstd::string &fileName) const {
|
||||
bool ret = false;
|
||||
do {
|
||||
CC_BREAK_IF(!_data);
|
||||
ret = _data->fileList.find(fileName) != _data->fileList.end();
|
||||
} while (false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char *ZipFile::getFileData(const ccstd::string &fileName, uint32_t *size) {
|
||||
unsigned char *buffer = nullptr;
|
||||
if (size) {
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
|
||||
do {
|
||||
CC_BREAK_IF(!(*zipFile));
|
||||
CC_BREAK_IF(fileName.empty());
|
||||
|
||||
auto it = _data->fileList.find(fileName);
|
||||
CC_BREAK_IF(it == _data->fileList.end());
|
||||
|
||||
ZipEntryInfo fileInfo = it->second;
|
||||
|
||||
int nRet = unzGoToFilePos(*zipFile, &fileInfo.pos);
|
||||
CC_BREAK_IF(UNZ_OK != nRet);
|
||||
|
||||
nRet = unzOpenCurrentFile(*zipFile);
|
||||
CC_BREAK_IF(UNZ_OK != nRet);
|
||||
|
||||
buffer = static_cast<unsigned char *>(malloc(fileInfo.uncompressed_size));
|
||||
int CC_UNUSED nSize = unzReadCurrentFile(*zipFile, buffer, static_cast<unsigned int>(fileInfo.uncompressed_size));
|
||||
CC_ASSERT(nSize == 0 || nSize == (int)fileInfo.uncompressed_size);
|
||||
|
||||
if (size) {
|
||||
*size = static_cast<uint32_t>(fileInfo.uncompressed_size);
|
||||
}
|
||||
unzCloseCurrentFile(*zipFile);
|
||||
} while (false);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool ZipFile::getFileData(const ccstd::string &fileName, ResizableBuffer *buffer) {
|
||||
bool res = false;
|
||||
do {
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
CC_BREAK_IF(!(*zipFile));
|
||||
CC_BREAK_IF(fileName.empty());
|
||||
|
||||
auto it = _data->fileList.find(fileName);
|
||||
CC_BREAK_IF(it == _data->fileList.end());
|
||||
|
||||
ZipEntryInfo fileInfo = it->second;
|
||||
|
||||
int nRet = unzGoToFilePos(*zipFile, &fileInfo.pos);
|
||||
CC_BREAK_IF(UNZ_OK != nRet);
|
||||
|
||||
nRet = unzOpenCurrentFile(*zipFile);
|
||||
CC_BREAK_IF(UNZ_OK != nRet);
|
||||
|
||||
buffer->resize(fileInfo.uncompressed_size);
|
||||
int CC_UNUSED nSize = unzReadCurrentFile(*zipFile, buffer->buffer(), static_cast<unsigned int>(fileInfo.uncompressed_size));
|
||||
CC_ASSERT(nSize == 0 || nSize == (int)fileInfo.uncompressed_size);
|
||||
unzCloseCurrentFile(*zipFile);
|
||||
res = true;
|
||||
} while (false);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
ccstd::string ZipFile::getFirstFilename() {
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
if (unzGoToFirstFile(*zipFile) != UNZ_OK) return EMPTY_FILE_NAME;
|
||||
ccstd::string path;
|
||||
unz_file_info info;
|
||||
getCurrentFileInfo(&path, &info);
|
||||
return path;
|
||||
}
|
||||
|
||||
ccstd::string ZipFile::getNextFilename() {
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
if (unzGoToNextFile(*zipFile) != UNZ_OK) return EMPTY_FILE_NAME;
|
||||
ccstd::string path;
|
||||
unz_file_info info;
|
||||
getCurrentFileInfo(&path, &info);
|
||||
return path;
|
||||
}
|
||||
|
||||
int ZipFile::getCurrentFileInfo(ccstd::string *filename, unz_file_info *info) {
|
||||
char path[FILENAME_MAX + 1];
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
int ret = unzGetCurrentFileInfo(*zipFile, info, path, sizeof(path), nullptr, 0, nullptr, 0);
|
||||
if (ret != UNZ_OK) {
|
||||
*filename = EMPTY_FILE_NAME;
|
||||
} else {
|
||||
filename->assign(path);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ZipFile::initWithBuffer(const void *buffer, uint32_t size) {
|
||||
if (!buffer || size == 0) return false;
|
||||
auto zipFile = _data->zipFile.lock();
|
||||
zlib_filefunc_def memoryFile = {nullptr};
|
||||
|
||||
std::unique_ptr<ourmemory_t> memfs(ccnew ourmemory_t{static_cast<char *>(const_cast<void *>(buffer)), static_cast<uint32_t>(size), 0, 0, 0});
|
||||
if (!memfs) return false;
|
||||
fill_memory_filefunc(&memoryFile, memfs.get());
|
||||
|
||||
*zipFile = unzOpen2(nullptr, &memoryFile);
|
||||
if (!(*zipFile)) return false;
|
||||
|
||||
setFilter(EMPTY_FILE_NAME);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
276
cocos/base/ZipUtils.h
Normal file
276
cocos/base/ZipUtils.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "platform/FileUtils.h"
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
#include "platform/android/FileUtils-android.h"
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
#ifndef _unz64_H
|
||||
using unz_file_info = struct unz_file_info_s;
|
||||
#endif
|
||||
|
||||
struct CCZHeader {
|
||||
unsigned char sig[4]; /** Signature. Should be 'CCZ!' 4 bytes. */
|
||||
uint16_t compression_type; /** Should be 0. */
|
||||
uint16_t version; /** Should be 2 (although version type==1 is also supported). */
|
||||
unsigned int reserved; /** Reserved for users. */
|
||||
unsigned int len; /** Size of the uncompressed file. */
|
||||
};
|
||||
|
||||
enum {
|
||||
CCZ_COMPRESSION_ZLIB, /** zlib format. */
|
||||
CCZ_COMPRESSION_BZIP2, /** bzip2 format (not supported yet). */
|
||||
CCZ_COMPRESSION_GZIP, /** gzip format (not supported yet). */
|
||||
CCZ_COMPRESSION_NONE, /** plain (not supported yet). */
|
||||
};
|
||||
|
||||
class CC_DLL ZipUtils {
|
||||
public:
|
||||
/**
|
||||
* Inflates either zlib or gzip deflated memory. The inflated memory is expected to be freed by the caller.
|
||||
*
|
||||
* It will allocate 256k for the destination buffer. If it is not enough it will multiply the previous buffer size per 2, until there is enough memory.
|
||||
*
|
||||
* @return The length of the deflated buffer.
|
||||
* @since v0.8.1
|
||||
*/
|
||||
static uint32_t inflateMemory(unsigned char *in, uint32_t inLength, unsigned char **out);
|
||||
|
||||
/**
|
||||
* Inflates either zlib or gzip deflated memory. The inflated memory is expected to be freed by the caller.
|
||||
*
|
||||
* @param outLengthHint It is assumed to be the needed room to allocate the inflated buffer.
|
||||
*
|
||||
* @return The length of the deflated buffer.
|
||||
* @since v1.0.0
|
||||
*/
|
||||
static uint32_t inflateMemoryWithHint(unsigned char *in, uint32_t inLength, unsigned char **out, uint32_t outLengthHint);
|
||||
|
||||
/**
|
||||
* Inflates a GZip file into memory.
|
||||
*
|
||||
* @return The length of the deflated buffer.
|
||||
* @since v0.99.5
|
||||
*/
|
||||
static int inflateGZipFile(const char *path, unsigned char **out);
|
||||
|
||||
/**
|
||||
* Test a file is a GZip format file or not.
|
||||
*
|
||||
* @return True is a GZip format file. false is not.
|
||||
* @since v3.0
|
||||
*/
|
||||
static bool isGZipFile(const char *path);
|
||||
|
||||
/**
|
||||
* Test the buffer is GZip format or not.
|
||||
*
|
||||
* @return True is GZip format. false is not.
|
||||
* @since v3.0
|
||||
*/
|
||||
static bool isGZipBuffer(const unsigned char *buffer, uint32_t len);
|
||||
|
||||
/**
|
||||
* Inflates a CCZ file into memory.
|
||||
*
|
||||
* @return The length of the deflated buffer.
|
||||
* @since v0.99.5
|
||||
*/
|
||||
static int inflateCCZFile(const char *path, unsigned char **out);
|
||||
|
||||
/**
|
||||
* Inflates a buffer with CCZ format into memory.
|
||||
*
|
||||
* @return The length of the deflated buffer.
|
||||
* @since v3.0
|
||||
*/
|
||||
static int inflateCCZBuffer(const unsigned char *buffer, uint32_t len, unsigned char **out);
|
||||
|
||||
/**
|
||||
* Test a file is a CCZ format file or not.
|
||||
*
|
||||
* @return True is a CCZ format file. false is not.
|
||||
* @since v3.0
|
||||
*/
|
||||
static bool isCCZFile(const char *path);
|
||||
|
||||
/**
|
||||
* Test the buffer is CCZ format or not.
|
||||
*
|
||||
* @return True is CCZ format. false is not.
|
||||
* @since v3.0
|
||||
*/
|
||||
static bool isCCZBuffer(const unsigned char *buffer, uint32_t len);
|
||||
|
||||
/**
|
||||
* Sets the pvr.ccz encryption key parts separately for added security.
|
||||
*
|
||||
* Example: If the key used to encrypt the pvr.ccz file is
|
||||
* 0xaaaaaaaabbbbbbbbccccccccdddddddd you will call this function 4
|
||||
* different times, preferably from 4 different source files, as follows
|
||||
*
|
||||
* ZipUtils::setPvrEncryptionKeyPart(0, 0xaaaaaaaa);
|
||||
* ZipUtils::setPvrEncryptionKeyPart(1, 0xbbbbbbbb);
|
||||
* ZipUtils::setPvrEncryptionKeyPart(2, 0xcccccccc);
|
||||
* ZipUtils::setPvrEncryptionKeyPart(3, 0xdddddddd);
|
||||
*
|
||||
* Splitting the key into 4 parts and calling the function from 4 different source
|
||||
* files increases the difficulty to reverse engineer the encryption key.
|
||||
* Be aware that encryption is *never* 100% secure and the key code
|
||||
* can be cracked by knowledgable persons.
|
||||
*
|
||||
* IMPORTANT: Be sure to call setPvrEncryptionKey or
|
||||
* setPvrEncryptionKeyPart with all of the key parts *before* loading
|
||||
* the sprite sheet or decryption will fail and the sprite sheet
|
||||
* will fail to load.
|
||||
*
|
||||
* @param index Part of the key [0..3].
|
||||
* @param value Value of the key part.
|
||||
*/
|
||||
static void setPvrEncryptionKeyPart(int index, unsigned int value);
|
||||
|
||||
/**
|
||||
* Sets the pvr.ccz encryption key.
|
||||
*
|
||||
* Example: If the key used to encrypt the pvr.ccz file is
|
||||
* 0xaaaaaaaabbbbbbbbccccccccdddddddd you will call this function with
|
||||
* the key split into 4 parts as follows
|
||||
*
|
||||
* ZipUtils::setPvrEncryptionKey(0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd);
|
||||
*
|
||||
* Note that using this function makes it easier to reverse engineer and discover
|
||||
* the complete key because the key parts are present in one function call.
|
||||
*
|
||||
* IMPORTANT: Be sure to call setPvrEncryptionKey or setPvrEncryptionKeyPart
|
||||
* with all of the key parts *before* loading the spritesheet or decryption
|
||||
* will fail and the sprite sheet will fail to load.
|
||||
*
|
||||
* @param keyPart1 The key value part 1.
|
||||
* @param keyPart2 The key value part 2.
|
||||
* @param keyPart3 The key value part 3.
|
||||
* @param keyPart4 The key value part 4.
|
||||
*/
|
||||
static void setPvrEncryptionKey(unsigned int keyPart1, unsigned int keyPart2, unsigned int keyPart3, unsigned int keyPart4);
|
||||
|
||||
private:
|
||||
static int inflateMemoryWithHint(unsigned char *in, uint32_t inLength, unsigned char **out, uint32_t *outLength, uint32_t outLengthHint);
|
||||
static inline void decodeEncodedPvr(unsigned int *data, uint32_t len);
|
||||
static inline unsigned int checksumPvr(const unsigned int *data, uint32_t len);
|
||||
|
||||
static unsigned int encryptedPvrKeyParts[4];
|
||||
static unsigned int encryptionKey[1024];
|
||||
static bool encryptionKeyIsValid;
|
||||
};
|
||||
|
||||
// forward declaration
|
||||
class ZipFilePrivate;
|
||||
struct unz_file_info_s;
|
||||
|
||||
/**
|
||||
* Zip file - reader helper class.
|
||||
*
|
||||
* It will cache the file list of a particular zip file with positions inside an archive,
|
||||
* so it would be much faster to read some particular files or to check their existence.
|
||||
*
|
||||
* @since v2.0.5
|
||||
*/
|
||||
class CC_DLL ZipFile {
|
||||
public:
|
||||
/**
|
||||
* Constructor, open zip file and store file list.
|
||||
*
|
||||
* @param zipFile Zip file name
|
||||
* @param filter The first part of file names, which should be accessible.
|
||||
* For example, "@assets/". Other files will be missed.
|
||||
*
|
||||
* @since v2.0.5
|
||||
*/
|
||||
explicit ZipFile(const ccstd::string &zipFile, const ccstd::string &filter = ccstd::string());
|
||||
virtual ~ZipFile();
|
||||
|
||||
/**
|
||||
* Regenerate accessible file list based on a new filter string.
|
||||
*
|
||||
* @param filter New filter string (first part of files names)
|
||||
* @return true whenever zip file is open successfully and it is possible to locate
|
||||
* at least the first file, false otherwise
|
||||
*
|
||||
* @since v2.0.5
|
||||
*/
|
||||
bool setFilter(const ccstd::string &filter);
|
||||
|
||||
/**
|
||||
* Check does a file exists or not in zip file
|
||||
*
|
||||
* @param fileName File to be checked on existence
|
||||
* @return true whenever file exists, false otherwise
|
||||
*
|
||||
* @since v2.0.5
|
||||
*/
|
||||
bool fileExists(const ccstd::string &fileName) const;
|
||||
|
||||
/**
|
||||
* Get resource file data from a zip file.
|
||||
* @param fileName File name
|
||||
* @param[out] pSize If the file read operation succeeds, it will be the data size, otherwise 0.
|
||||
* @return Upon success, a pointer to the data is returned, otherwise nullptr.
|
||||
* @warning Recall: you are responsible for calling free() on any Non-nullptr pointer returned.
|
||||
*
|
||||
* @since v2.0.5
|
||||
*/
|
||||
unsigned char *getFileData(const ccstd::string &fileName, uint32_t *size);
|
||||
|
||||
/**
|
||||
* Get resource file data from a zip file.
|
||||
* @param fileName File name
|
||||
* @param[out] buffer If the file read operation succeeds, if will contain the file data.
|
||||
* @return True if successful.
|
||||
*/
|
||||
bool getFileData(const ccstd::string &fileName, ResizableBuffer *buffer);
|
||||
|
||||
ccstd::string getFirstFilename();
|
||||
ccstd::string getNextFilename();
|
||||
|
||||
static ZipFile *createWithBuffer(const void *buffer, uint32_t size);
|
||||
|
||||
private:
|
||||
/* Only used internal for createWithBuffer() */
|
||||
ZipFile();
|
||||
|
||||
bool initWithBuffer(const void *buffer, uint32_t size);
|
||||
int getCurrentFileInfo(ccstd::string *filename, unz_file_info *info);
|
||||
|
||||
/** Internal data like zip file pointer / file list array and so on */
|
||||
ZipFilePrivate *_data{nullptr};
|
||||
};
|
||||
} // end of namespace cc
|
||||
60
cocos/base/astc.cpp
Normal file
60
cocos/base/astc.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/astc.h"
|
||||
#include "platform/Image.h"
|
||||
|
||||
static const unsigned int MAGIC = 0x5CA1AB13;
|
||||
static const astc_byte ASTC_HEADER_SIZE_X_BEGIN = 7;
|
||||
static const astc_byte ASTC_HEADER_SIZE_Y_BEGIN = 10;
|
||||
|
||||
bool astcIsValid(const astc_byte *pHeader) {
|
||||
uint32_t magicval = static_cast<uint32_t>(pHeader[0]) +
|
||||
static_cast<uint32_t>(pHeader[1]) * 256 +
|
||||
static_cast<uint32_t>(pHeader[2]) * 65536 +
|
||||
static_cast<uint32_t>(pHeader[3]) * 16777216;
|
||||
|
||||
if (magicval != MAGIC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int xdim = pHeader[ASTC_HEADER_MAGIC];
|
||||
int ydim = pHeader[ASTC_HEADER_MAGIC + 1];
|
||||
int zdim = pHeader[ASTC_HEADER_MAGIC + 2];
|
||||
return !((xdim < 3 || xdim > 6 || ydim < 3 || ydim > 6 || zdim < 3 || zdim > 6) &&
|
||||
(xdim < 4 || xdim == 7 || xdim == 9 || xdim == 11 || xdim > 12 ||
|
||||
ydim < 4 || ydim == 7 || ydim == 9 || ydim == 11 || ydim > 12 || zdim != 1));
|
||||
}
|
||||
|
||||
int astcGetWidth(const astc_byte *pHeader) {
|
||||
int xsize = pHeader[ASTC_HEADER_SIZE_X_BEGIN] + (pHeader[ASTC_HEADER_SIZE_X_BEGIN + 1] * 256) + (pHeader[ASTC_HEADER_SIZE_X_BEGIN + 2] * 65536);
|
||||
return xsize;
|
||||
}
|
||||
|
||||
int astcGetHeight(const astc_byte *pHeader) {
|
||||
int ysize = pHeader[ASTC_HEADER_SIZE_Y_BEGIN] + (pHeader[ASTC_HEADER_SIZE_Y_BEGIN + 1] * 256) + (pHeader[ASTC_HEADER_SIZE_Y_BEGIN + 2] * 65536);
|
||||
return ysize;
|
||||
}
|
||||
50
cocos/base/astc.h
Normal file
50
cocos/base/astc.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#pragma once
|
||||
|
||||
using astc_byte = unsigned char;
|
||||
using astc_uint32 = unsigned int;
|
||||
|
||||
// Size of a ASTC header
|
||||
|
||||
#define ASTC_HEADER_SIZE 16
|
||||
|
||||
#define ASTC_HEADER_MAGIC 4
|
||||
|
||||
// Check if a ASTC header is correctly formatted
|
||||
|
||||
bool astcIsValid(const astc_byte *pHeader);
|
||||
|
||||
// Read the image width from a ASTC header
|
||||
|
||||
int astcGetWidth(const astc_byte *pHeader);
|
||||
|
||||
// Read the image height from a ASTC header
|
||||
|
||||
int astcGetHeight(const astc_byte *pHeader);
|
||||
179
cocos/base/base64.cpp
Normal file
179
cocos/base/base64.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/base64.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
ccstd::string alphabet{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};
|
||||
|
||||
int doBase64Decode(const unsigned char *input, unsigned int inputLen, unsigned char *output, unsigned int *outputLen) {
|
||||
static ccstd::vector<char> inalphabet(256);
|
||||
static ccstd::vector<char> decoder(256);
|
||||
int i;
|
||||
int bits;
|
||||
int c = 0;
|
||||
int charCount;
|
||||
int errors = 0;
|
||||
unsigned int inputIdx = 0;
|
||||
unsigned int outputIdx = 0;
|
||||
int length = static_cast<int>(alphabet.length());
|
||||
for (i = length - 1; i >= 0; i--) {
|
||||
inalphabet[alphabet[i]] = 1;
|
||||
decoder[alphabet[i]] = i;
|
||||
}
|
||||
|
||||
charCount = 0;
|
||||
bits = 0;
|
||||
for (inputIdx = 0; inputIdx < inputLen; inputIdx++) {
|
||||
c = input[inputIdx];
|
||||
if (c == '=') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c > 255 || !inalphabet[c]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bits += decoder[c];
|
||||
++charCount;
|
||||
if (charCount == 4) {
|
||||
output[outputIdx++] = (bits >> 16);
|
||||
output[outputIdx++] = ((bits >> 8) & 0xff);
|
||||
output[outputIdx++] = (bits & 0xff);
|
||||
bits = 0;
|
||||
charCount = 0;
|
||||
} else {
|
||||
bits <<= 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == '=') {
|
||||
switch (charCount) {
|
||||
case 1:
|
||||
#if (CC_PLATFORM != CC_PLATFORM_BADA)
|
||||
fprintf(stderr, "base64Decode: encoding incomplete: at least 2 bits missing");
|
||||
#endif
|
||||
++errors;
|
||||
break;
|
||||
case 2:
|
||||
output[outputIdx++] = (bits >> 10);
|
||||
break;
|
||||
case 3:
|
||||
output[outputIdx++] = (bits >> 16);
|
||||
output[outputIdx++] = ((bits >> 8) & 0xff);
|
||||
break;
|
||||
}
|
||||
} else if (inputIdx < inputLen) {
|
||||
if (charCount) {
|
||||
#if (CC_PLATFORM != CC_PLATFORM_BADA)
|
||||
fprintf(stderr, "base64 encoding incomplete: at least %d bits truncated",
|
||||
((4 - charCount) * 6));
|
||||
#endif
|
||||
++errors;
|
||||
}
|
||||
}
|
||||
|
||||
*outputLen = outputIdx;
|
||||
return errors;
|
||||
}
|
||||
|
||||
void doBase64Encode(const unsigned char *input, unsigned int inputLen, char *output) {
|
||||
unsigned int charCount;
|
||||
unsigned int bits;
|
||||
unsigned int inputIdx = 0;
|
||||
unsigned int outputIdx = 0;
|
||||
|
||||
charCount = 0;
|
||||
bits = 0;
|
||||
for (inputIdx = 0; inputIdx < inputLen; inputIdx++) {
|
||||
bits |= input[inputIdx];
|
||||
|
||||
charCount++;
|
||||
if (charCount == 3) {
|
||||
output[outputIdx++] = alphabet[(bits >> 18) & 0x3f];
|
||||
output[outputIdx++] = alphabet[(bits >> 12) & 0x3f];
|
||||
output[outputIdx++] = alphabet[(bits >> 6) & 0x3f];
|
||||
output[outputIdx++] = alphabet[bits & 0x3f];
|
||||
bits = 0;
|
||||
charCount = 0;
|
||||
} else {
|
||||
bits <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (charCount) {
|
||||
if (charCount == 1) {
|
||||
bits <<= 8;
|
||||
}
|
||||
|
||||
output[outputIdx++] = alphabet[(bits >> 18) & 0x3f];
|
||||
output[outputIdx++] = alphabet[(bits >> 12) & 0x3f];
|
||||
if (charCount > 1) {
|
||||
output[outputIdx++] = alphabet[(bits >> 6) & 0x3f];
|
||||
} else {
|
||||
output[outputIdx++] = '=';
|
||||
}
|
||||
output[outputIdx++] = '=';
|
||||
}
|
||||
|
||||
output[outputIdx++] = 0;
|
||||
}
|
||||
|
||||
int base64Decode(const unsigned char *in, unsigned int inLength, unsigned char **out) {
|
||||
unsigned int outLength = 0;
|
||||
|
||||
//should be enough to store 6-bit buffers in 8-bit buffers
|
||||
*out = static_cast<unsigned char *>(malloc(inLength / 4 * 3 + 1));
|
||||
if (*out) {
|
||||
int ret = doBase64Decode(in, inLength, *out, &outLength);
|
||||
|
||||
if (ret > 0) {
|
||||
free(*out);
|
||||
*out = nullptr;
|
||||
outLength = 0;
|
||||
}
|
||||
}
|
||||
return static_cast<int>(outLength);
|
||||
}
|
||||
|
||||
int base64Encode(const unsigned char *in, unsigned int inLength, char **out) {
|
||||
unsigned int outLength = (inLength + 2) / 3 * 4;
|
||||
|
||||
//should be enough to store 8-bit buffers in 6-bit buffers
|
||||
*out = static_cast<char *>(malloc(outLength + 1));
|
||||
if (*out) {
|
||||
doBase64Encode(in, inLength, *out);
|
||||
}
|
||||
return static_cast<int>(outLength);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
58
cocos/base/base64.h
Normal file
58
cocos/base/base64.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
/**
|
||||
* Decodes a 64base encoded memory. The decoded memory is
|
||||
* expected to be freed by the caller by calling `free()`
|
||||
*
|
||||
* @returns the length of the out buffer
|
||||
*/
|
||||
int CC_DLL base64Decode(const unsigned char *in, unsigned int inLength, unsigned char **out);
|
||||
|
||||
/**
|
||||
* Encodes bytes into a 64base encoded memory with terminating '\0' character.
|
||||
* The encoded memory is expected to be freed by the caller by calling `free()`
|
||||
*
|
||||
* @returns the length of the out buffer
|
||||
*
|
||||
*/
|
||||
int CC_DLL base64Encode(const unsigned char *in, unsigned int inLength, char **out);
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
387
cocos/base/csscolorparser.cpp
Normal file
387
cocos/base/csscolorparser.cpp
Normal file
@@ -0,0 +1,387 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// (c) Dean McNamee <dean@gmail.com>, 2012.
|
||||
// C++ port by Mapbox, Konstantin Käfer <mail@kkaefer.com>, 2014-2017.
|
||||
//
|
||||
// https://github.com/deanm/css-color-parser-js
|
||||
// https://github.com/kkaefer/css-color-parser-cpp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#include "csscolorparser.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace CSSColorParser {
|
||||
|
||||
// http://www.w3.org/TR/css3-color/
|
||||
struct NamedColor {
|
||||
const char *name;
|
||||
Color color;
|
||||
};
|
||||
|
||||
const ccstd::vector<NamedColor> NAMED_COLORS = {
|
||||
{"transparent", {0, 0, 0, 0}},
|
||||
{"aliceblue", {240, 248, 255, 1}},
|
||||
{"antiquewhite", {250, 235, 215, 1}},
|
||||
{"aqua", {0, 255, 255, 1}},
|
||||
{"aquamarine", {127, 255, 212, 1}},
|
||||
{"azure", {240, 255, 255, 1}},
|
||||
{"beige", {245, 245, 220, 1}},
|
||||
{"bisque", {255, 228, 196, 1}},
|
||||
{"black", {0, 0, 0, 1}},
|
||||
{"blanchedalmond", {255, 235, 205, 1}},
|
||||
{"blue", {0, 0, 255, 1}},
|
||||
{"blueviolet", {138, 43, 226, 1}},
|
||||
{"brown", {165, 42, 42, 1}},
|
||||
{"burlywood", {222, 184, 135, 1}},
|
||||
{"cadetblue", {95, 158, 160, 1}},
|
||||
{"chartreuse", {127, 255, 0, 1}},
|
||||
{"chocolate", {210, 105, 30, 1}},
|
||||
{"coral", {255, 127, 80, 1}},
|
||||
{"cornflowerblue", {100, 149, 237, 1}},
|
||||
{"cornsilk", {255, 248, 220, 1}},
|
||||
{"crimson", {220, 20, 60, 1}},
|
||||
{"cyan", {0, 255, 255, 1}},
|
||||
{"darkblue", {0, 0, 139, 1}},
|
||||
{"darkcyan", {0, 139, 139, 1}},
|
||||
{"darkgoldenrod", {184, 134, 11, 1}},
|
||||
{"darkgray", {169, 169, 169, 1}},
|
||||
{"darkgreen", {0, 100, 0, 1}},
|
||||
{"darkgrey", {169, 169, 169, 1}},
|
||||
{"darkkhaki", {189, 183, 107, 1}},
|
||||
{"darkmagenta", {139, 0, 139, 1}},
|
||||
{"darkolivegreen", {85, 107, 47, 1}},
|
||||
{"darkorange", {255, 140, 0, 1}},
|
||||
{"darkorchid", {153, 50, 204, 1}},
|
||||
{"darkred", {139, 0, 0, 1}},
|
||||
{"darksalmon", {233, 150, 122, 1}},
|
||||
{"darkseagreen", {143, 188, 143, 1}},
|
||||
{"darkslateblue", {72, 61, 139, 1}},
|
||||
{"darkslategray", {47, 79, 79, 1}},
|
||||
{"darkslategrey", {47, 79, 79, 1}},
|
||||
{"darkturquoise", {0, 206, 209, 1}},
|
||||
{"darkviolet", {148, 0, 211, 1}},
|
||||
{"deeppink", {255, 20, 147, 1}},
|
||||
{"deepskyblue", {0, 191, 255, 1}},
|
||||
{"dimgray", {105, 105, 105, 1}},
|
||||
{"dimgrey", {105, 105, 105, 1}},
|
||||
{"dodgerblue", {30, 144, 255, 1}},
|
||||
{"firebrick", {178, 34, 34, 1}},
|
||||
{"floralwhite", {255, 250, 240, 1}},
|
||||
{"forestgreen", {34, 139, 34, 1}},
|
||||
{"fuchsia", {255, 0, 255, 1}},
|
||||
{"gainsboro", {220, 220, 220, 1}},
|
||||
{"ghostwhite", {248, 248, 255, 1}},
|
||||
{"gold", {255, 215, 0, 1}},
|
||||
{"goldenrod", {218, 165, 32, 1}},
|
||||
{"gray", {128, 128, 128, 1}},
|
||||
{"green", {0, 128, 0, 1}},
|
||||
{"greenyellow", {173, 255, 47, 1}},
|
||||
{"grey", {128, 128, 128, 1}},
|
||||
{"honeydew", {240, 255, 240, 1}},
|
||||
{"hotpink", {255, 105, 180, 1}},
|
||||
{"indianred", {205, 92, 92, 1}},
|
||||
{"indigo", {75, 0, 130, 1}},
|
||||
{"ivory", {255, 255, 240, 1}},
|
||||
{"khaki", {240, 230, 140, 1}},
|
||||
{"lavender", {230, 230, 250, 1}},
|
||||
{"lavenderblush", {255, 240, 245, 1}},
|
||||
{"lawngreen", {124, 252, 0, 1}},
|
||||
{"lemonchiffon", {255, 250, 205, 1}},
|
||||
{"lightblue", {173, 216, 230, 1}},
|
||||
{"lightcoral", {240, 128, 128, 1}},
|
||||
{"lightcyan", {224, 255, 255, 1}},
|
||||
{"lightgoldenrodyellow", {250, 250, 210, 1}},
|
||||
{"lightgray", {211, 211, 211, 1}},
|
||||
{"lightgreen", {144, 238, 144, 1}},
|
||||
{"lightgrey", {211, 211, 211, 1}},
|
||||
{"lightpink", {255, 182, 193, 1}},
|
||||
{"lightsalmon", {255, 160, 122, 1}},
|
||||
{"lightseagreen", {32, 178, 170, 1}},
|
||||
{"lightskyblue", {135, 206, 250, 1}},
|
||||
{"lightslategray", {119, 136, 153, 1}},
|
||||
{"lightslategrey", {119, 136, 153, 1}},
|
||||
{"lightsteelblue", {176, 196, 222, 1}},
|
||||
{"lightyellow", {255, 255, 224, 1}},
|
||||
{"lime", {0, 255, 0, 1}},
|
||||
{"limegreen", {50, 205, 50, 1}},
|
||||
{"linen", {250, 240, 230, 1}},
|
||||
{"magenta", {255, 0, 255, 1}},
|
||||
{"maroon", {128, 0, 0, 1}},
|
||||
{"mediumaquamarine", {102, 205, 170, 1}},
|
||||
{"mediumblue", {0, 0, 205, 1}},
|
||||
{"mediumorchid", {186, 85, 211, 1}},
|
||||
{"mediumpurple", {147, 112, 219, 1}},
|
||||
{"mediumseagreen", {60, 179, 113, 1}},
|
||||
{"mediumslateblue", {123, 104, 238, 1}},
|
||||
{"mediumspringgreen", {0, 250, 154, 1}},
|
||||
{"mediumturquoise", {72, 209, 204, 1}},
|
||||
{"mediumvioletred", {199, 21, 133, 1}},
|
||||
{"midnightblue", {25, 25, 112, 1}},
|
||||
{"mintcream", {245, 255, 250, 1}},
|
||||
{"mistyrose", {255, 228, 225, 1}},
|
||||
{"moccasin", {255, 228, 181, 1}},
|
||||
{"navajowhite", {255, 222, 173, 1}},
|
||||
{"navy", {0, 0, 128, 1}},
|
||||
{"oldlace", {253, 245, 230, 1}},
|
||||
{"olive", {128, 128, 0, 1}},
|
||||
{"olivedrab", {107, 142, 35, 1}},
|
||||
{"orange", {255, 165, 0, 1}},
|
||||
{"orangered", {255, 69, 0, 1}},
|
||||
{"orchid", {218, 112, 214, 1}},
|
||||
{"palegoldenrod", {238, 232, 170, 1}},
|
||||
{"palegreen", {152, 251, 152, 1}},
|
||||
{"paleturquoise", {175, 238, 238, 1}},
|
||||
{"palevioletred", {219, 112, 147, 1}},
|
||||
{"papayawhip", {255, 239, 213, 1}},
|
||||
{"peachpuff", {255, 218, 185, 1}},
|
||||
{"peru", {205, 133, 63, 1}},
|
||||
{"pink", {255, 192, 203, 1}},
|
||||
{"plum", {221, 160, 221, 1}},
|
||||
{"powderblue", {176, 224, 230, 1}},
|
||||
{"purple", {128, 0, 128, 1}},
|
||||
{"red", {255, 0, 0, 1}},
|
||||
{"rosybrown", {188, 143, 143, 1}},
|
||||
{"royalblue", {65, 105, 225, 1}},
|
||||
{"saddlebrown", {139, 69, 19, 1}},
|
||||
{"salmon", {250, 128, 114, 1}},
|
||||
{"sandybrown", {244, 164, 96, 1}},
|
||||
{"seagreen", {46, 139, 87, 1}},
|
||||
{"seashell", {255, 245, 238, 1}},
|
||||
{"sienna", {160, 82, 45, 1}},
|
||||
{"silver", {192, 192, 192, 1}},
|
||||
{"skyblue", {135, 206, 235, 1}},
|
||||
{"slateblue", {106, 90, 205, 1}},
|
||||
{"slategray", {112, 128, 144, 1}},
|
||||
{"slategrey", {112, 128, 144, 1}},
|
||||
{"snow", {255, 250, 250, 1}},
|
||||
{"springgreen", {0, 255, 127, 1}},
|
||||
{"steelblue", {70, 130, 180, 1}},
|
||||
{"tan", {210, 180, 140, 1}},
|
||||
{"teal", {0, 128, 128, 1}},
|
||||
{"thistle", {216, 191, 216, 1}},
|
||||
{"tomato", {255, 99, 71, 1}},
|
||||
{"turquoise", {64, 224, 208, 1}},
|
||||
{"violet", {238, 130, 238, 1}},
|
||||
{"wheat", {245, 222, 179, 1}},
|
||||
{"white", {255, 255, 255, 1}},
|
||||
{"whitesmoke", {245, 245, 245, 1}},
|
||||
{"yellow", {255, 255, 0, 1}},
|
||||
{"yellowgreen", {154, 205, 50, 1}}};
|
||||
|
||||
template <typename T>
|
||||
uint8_t clampCssByte(T i) { // Clamp to integer 0 .. 255.
|
||||
i = static_cast<T>(::round(i)); // Seems to be what Chrome does (vs truncation).
|
||||
return static_cast<uint8_t>(i < 0 ? 0 : i > 255 ? 255
|
||||
: i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float clampCssFloat(T f) { // Clamp to float 0.0 .. 1.0.
|
||||
return f < 0 ? 0 : f > 1 ? 1
|
||||
: float(f);
|
||||
}
|
||||
|
||||
float parseFloat(const ccstd::string &str) {
|
||||
return strtof(str.c_str(), nullptr);
|
||||
}
|
||||
|
||||
int64_t parseInt(const ccstd::string &str, uint8_t base = 10) {
|
||||
return strtoll(str.c_str(), nullptr, base);
|
||||
}
|
||||
|
||||
uint8_t parseCssInt(const ccstd::string &str) { // int or percentage.
|
||||
if (str.length() && str.back() == '%') {
|
||||
return clampCssByte(parseFloat(str) / 100.0f * 255.0f);
|
||||
}
|
||||
return clampCssByte(parseInt(str));
|
||||
}
|
||||
|
||||
float parseCssFloat(const ccstd::string &str) { // float or percentage.
|
||||
if (str.length() && str.back() == '%') {
|
||||
return clampCssFloat(parseFloat(str) / 100.0f);
|
||||
}
|
||||
return clampCssFloat(parseFloat(str));
|
||||
}
|
||||
|
||||
float cssHueToRgb(float m1, float m2, float h) {
|
||||
if (h < 0.0f) {
|
||||
h += 1.0f;
|
||||
} else if (h > 1.0f) {
|
||||
h -= 1.0f;
|
||||
}
|
||||
|
||||
if (h * 6.0f < 1.0f) {
|
||||
return m1 + (m2 - m1) * h * 6.0f;
|
||||
}
|
||||
if (h * 2.0f < 1.0f) {
|
||||
return m2;
|
||||
}
|
||||
if (h * 3.0f < 2.0f) {
|
||||
return m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f;
|
||||
}
|
||||
return m1;
|
||||
}
|
||||
|
||||
ccstd::vector<ccstd::string> split(const ccstd::string &s, char delim) {
|
||||
ccstd::vector<ccstd::string> elems;
|
||||
std::stringstream ss(s);
|
||||
ccstd::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
|
||||
Color parse(const ccstd::string &cssStr) {
|
||||
ccstd::string str = cssStr;
|
||||
|
||||
// Remove all whitespace, not compliant, but should just be more accepting.
|
||||
str.erase(std::remove(str.begin(), str.end(), ' '), str.end());
|
||||
|
||||
// Convert to lowercase.
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
|
||||
for (const auto &namedColor : NAMED_COLORS) {
|
||||
if (str == namedColor.name) {
|
||||
return namedColor.color;
|
||||
}
|
||||
}
|
||||
|
||||
// #abc and #abc123 syntax.
|
||||
if (str.length() && str.front() == '#') {
|
||||
if (str.length() == 4) {
|
||||
int64_t iv =
|
||||
parseInt(str.substr(1), 16); // REFINE(deanm): Stricter parsing.
|
||||
if (!(iv >= 0 && iv <= 0xfff)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return Color(
|
||||
static_cast<uint8_t>(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)),
|
||||
static_cast<uint8_t>((iv & 0xf0) | ((iv & 0xf0) >> 4)),
|
||||
static_cast<uint8_t>((iv & 0xf) | ((iv & 0xf) << 4)), 1);
|
||||
}
|
||||
|
||||
if (str.length() == 7) {
|
||||
int64_t iv = parseInt(str.substr(1), 16); // REFINE(deanm): Stricter parsing.
|
||||
if (!(iv >= 0 && iv <= 0xffffff)) {
|
||||
return {}; // Covers NaN.
|
||||
}
|
||||
|
||||
return Color(static_cast<uint8_t>((iv & 0xff0000) >> 16),
|
||||
static_cast<uint8_t>((iv & 0xff00) >> 8),
|
||||
static_cast<uint8_t>(iv & 0xff), 1);
|
||||
}
|
||||
|
||||
return Color();
|
||||
}
|
||||
|
||||
size_t op = str.find_first_of('(');
|
||||
size_t ep = str.find_first_of(')');
|
||||
if (op != ccstd::string::npos && ep + 1 == str.length()) {
|
||||
const ccstd::string fname = str.substr(0, op);
|
||||
const ccstd::vector<ccstd::string> params =
|
||||
split(str.substr(op + 1, ep - (op + 1)), ',');
|
||||
|
||||
float alpha = 1.0f;
|
||||
|
||||
if (fname == "rgba" || fname == "rgb") {
|
||||
if (fname == "rgba") {
|
||||
if (params.size() != 4) {
|
||||
return {};
|
||||
}
|
||||
alpha = parseCssFloat(params.back());
|
||||
} else {
|
||||
if (params.size() != 3) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return Color(parseCssInt(params[0]), parseCssInt(params[1]),
|
||||
parseCssInt(params[2]), alpha);
|
||||
}
|
||||
|
||||
if (fname == "hsla" || fname == "hsl") {
|
||||
if (fname == "hsla") {
|
||||
if (params.size() != 4) {
|
||||
return {};
|
||||
}
|
||||
alpha = parseCssFloat(params.back());
|
||||
} else {
|
||||
if (params.size() != 3) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
float h = parseFloat(params[0]) / 360.0f;
|
||||
while (h < 0.0f) {
|
||||
++h;
|
||||
}
|
||||
while (h > 1.0f) {
|
||||
--h;
|
||||
}
|
||||
|
||||
// NOTE(deanm): According to the CSS spec s/l should only be
|
||||
// percentages, but we don't bother and let float or percentage.
|
||||
float s = parseCssFloat(params[1]);
|
||||
float l = parseCssFloat(params[2]);
|
||||
|
||||
float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s;
|
||||
float m1 = l * 2.0f - m2;
|
||||
|
||||
return Color(
|
||||
clampCssByte(cssHueToRgb(m1, m2, h + 1.0f / 3.0f) * 255.0f),
|
||||
clampCssByte(cssHueToRgb(m1, m2, h) * 255.0f),
|
||||
clampCssByte(cssHueToRgb(m1, m2, h - 1.0f / 3.0f) * 255.0f),
|
||||
alpha);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace CSSColorParser
|
||||
76
cocos/base/csscolorparser.h
Normal file
76
cocos/base/csscolorparser.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// (c) Dean McNamee <dean@gmail.com>, 2012.
|
||||
// C++ port by Mapbox, Konstantin Käfer <mail@kkaefer.com>, 2014-2017.
|
||||
//
|
||||
// https://github.com/deanm/css-color-parser-js
|
||||
// https://github.com/kkaefer/css-color-parser-cpp
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include "base/std/container/string.h"
|
||||
|
||||
namespace CSSColorParser {
|
||||
|
||||
struct Color {
|
||||
inline Color() = default;
|
||||
inline Color(unsigned char red, unsigned char green, unsigned char blue, float alpha)
|
||||
: r(red), g(green), b(blue), a(alpha > 1 ? 1 : alpha < 0 ? 0
|
||||
: alpha) {
|
||||
}
|
||||
unsigned char r = 0, g = 0, b = 0;
|
||||
float a = 1.0f;
|
||||
};
|
||||
|
||||
inline bool operator==(const Color &lhs, const Color &rhs) {
|
||||
return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && ::fabs(lhs.a - rhs.a) < 0.0001f;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Color &lhs, const Color &rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
Color parse(const ccstd::string &cssStr);
|
||||
|
||||
} // namespace CSSColorParser
|
||||
83
cocos/base/etc1.cpp
Normal file
83
cocos/base/etc1.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// Copyright 2009 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "base/etc1.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const char kMagic[] = {'P', 'K', 'M', ' ', '1', '0'};
|
||||
|
||||
static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
|
||||
static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
|
||||
static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
|
||||
static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
|
||||
static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;
|
||||
|
||||
static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0;
|
||||
|
||||
static etc1_uint32 readBEUint16(const etc1_byte *pIn) {
|
||||
return (pIn[0] << 8) | pIn[1];
|
||||
}
|
||||
|
||||
// Check if a PKM header is correctly formatted.
|
||||
|
||||
etc1_bool etc1_pkm_is_valid(const etc1_byte *pHeader) {
|
||||
if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
|
||||
return false;
|
||||
}
|
||||
etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET);
|
||||
etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET);
|
||||
etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET);
|
||||
etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
|
||||
etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
|
||||
return format == ETC1_RGB_NO_MIPMAPS &&
|
||||
encodedWidth >= width && encodedWidth - width < 4 &&
|
||||
encodedHeight >= height && encodedHeight - height < 4;
|
||||
}
|
||||
|
||||
// Read the image width from a PKM header
|
||||
|
||||
etc1_uint32 etc1_pkm_get_width(const etc1_byte *pHeader) {
|
||||
return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
|
||||
}
|
||||
|
||||
// Read the image height from a PKM header
|
||||
|
||||
etc1_uint32 etc1_pkm_get_height(const etc1_byte *pHeader) {
|
||||
return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
|
||||
}
|
||||
78
cocos/base/etc1.h
Normal file
78
cocos/base/etc1.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
// Copyright 2009 Google Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef __etc1_h__
|
||||
#define __etc1_h__
|
||||
/// @cond DO_NOT_SHOW
|
||||
|
||||
#define ETC1_ENCODED_BLOCK_SIZE 8
|
||||
#define ETC1_DECODED_BLOCK_SIZE 48
|
||||
|
||||
#ifndef ETC1_RGB8_OES
|
||||
#define ETC1_RGB8_OES 0x8D64
|
||||
#endif
|
||||
|
||||
typedef unsigned char etc1_byte;
|
||||
typedef int etc1_bool;
|
||||
typedef unsigned int etc1_uint32;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// Size of a PKM header, in bytes.
|
||||
|
||||
#define ETC_PKM_HEADER_SIZE 16
|
||||
|
||||
// Check if a PKM header is correctly formatted.
|
||||
|
||||
etc1_bool etc1_pkm_is_valid(const etc1_byte *pHeader);
|
||||
|
||||
// Read the image width from a PKM header
|
||||
|
||||
etc1_uint32 etc1_pkm_get_width(const etc1_byte *pHeader);
|
||||
|
||||
// Read the image height from a PKM header
|
||||
|
||||
etc1_uint32 etc1_pkm_get_height(const etc1_byte *pHeader);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
#endif
|
||||
73
cocos/base/etc2.cpp
Normal file
73
cocos/base/etc2.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/etc2.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char kMagic[] = {'P', 'K', 'M', ' ', '2', '0'};
|
||||
|
||||
static const etc2_uint32 ETC2_PKM_FORMAT_OFFSET = 6;
|
||||
static const etc2_uint32 ETC2_PKM_ENCODED_WIDTH_OFFSET = 8;
|
||||
static const etc2_uint32 ETC2_PKM_ENCODED_HEIGHT_OFFSET = 10;
|
||||
static const etc2_uint32 ETC2_PKM_WIDTH_OFFSET = 12;
|
||||
static const etc2_uint32 ETC2_PKM_HEIGHT_OFFSET = 14;
|
||||
|
||||
static etc2_uint32 readBEUint16(const etc2_byte *pIn) {
|
||||
return (pIn[0] << 8) | pIn[1];
|
||||
}
|
||||
|
||||
// Check if a PKM header is correctly formatted.
|
||||
|
||||
etc2_bool etc2_pkm_is_valid(const etc2_byte *pHeader) {
|
||||
if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
|
||||
return false;
|
||||
}
|
||||
etc2_uint32 format = readBEUint16(pHeader + ETC2_PKM_FORMAT_OFFSET);
|
||||
etc2_uint32 encodedWidth = readBEUint16(pHeader + ETC2_PKM_ENCODED_WIDTH_OFFSET);
|
||||
etc2_uint32 encodedHeight = readBEUint16(pHeader + ETC2_PKM_ENCODED_HEIGHT_OFFSET);
|
||||
etc2_uint32 width = readBEUint16(pHeader + ETC2_PKM_WIDTH_OFFSET);
|
||||
etc2_uint32 height = readBEUint16(pHeader + ETC2_PKM_HEIGHT_OFFSET);
|
||||
return (format == ETC2_RGB_NO_MIPMAPS || format == ETC2_RGBA_NO_MIPMAPS) &&
|
||||
encodedWidth >= width && encodedWidth - width < 4 &&
|
||||
encodedHeight >= height && encodedHeight - height < 4;
|
||||
}
|
||||
|
||||
// Read the image width from a PKM header
|
||||
|
||||
etc2_uint32 etc2_pkm_get_width(const etc2_byte *pHeader) {
|
||||
return readBEUint16(pHeader + ETC2_PKM_WIDTH_OFFSET);
|
||||
}
|
||||
|
||||
// Read the image height from a PKM header
|
||||
|
||||
etc2_uint32 etc2_pkm_get_height(const etc2_byte *pHeader) {
|
||||
return readBEUint16(pHeader + ETC2_PKM_HEIGHT_OFFSET);
|
||||
}
|
||||
|
||||
etc2_uint32 etc2_pkm_get_format(const uint8_t *pHeader) {
|
||||
return readBEUint16(pHeader + ETC2_PKM_FORMAT_OFFSET);
|
||||
}
|
||||
75
cocos/base/etc2.h
Normal file
75
cocos/base/etc2.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2010-2012 cocos2d-x.org
|
||||
Copyright (c) 2013-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __etc2_h__
|
||||
#define __etc2_h__
|
||||
/// @cond DO_NOT_SHOW
|
||||
|
||||
typedef unsigned char etc2_byte;
|
||||
typedef int etc2_bool;
|
||||
typedef unsigned int etc2_uint32;
|
||||
|
||||
#ifndef GL_COMPRESSED_RGB8_ETC2
|
||||
#define GL_COMPRESSED_RGB8_ETC2 0x9274
|
||||
#endif
|
||||
|
||||
#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
|
||||
#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Size of a PKM header, in bytes.
|
||||
|
||||
#define ETC2_PKM_HEADER_SIZE 16
|
||||
|
||||
#define ETC2_RGB_NO_MIPMAPS 1
|
||||
#define ETC2_RGBA_NO_MIPMAPS 3
|
||||
|
||||
// Check if a PKM header is correctly formatted.
|
||||
|
||||
etc2_bool etc2_pkm_is_valid(const etc2_byte *pHeader);
|
||||
|
||||
// Read the image width from a PKM header
|
||||
|
||||
etc2_uint32 etc2_pkm_get_width(const etc2_byte *pHeader);
|
||||
|
||||
// Read the image height from a PKM header
|
||||
|
||||
etc2_uint32 etc2_pkm_get_height(const etc2_byte *pHeader);
|
||||
|
||||
// Read the image format from a PKM header
|
||||
|
||||
etc2_uint32 etc2_pkm_get_format(const etc2_byte *pHeader);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/// @endcond
|
||||
#endif
|
||||
51
cocos/base/job-system/JobSystem.h
Normal file
51
cocos/base/job-system/JobSystem.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if CC_USE_JOB_SYSTEM_TASKFLOW
|
||||
#include "job-system-taskflow/TFJobGraph.h"
|
||||
#include "job-system-taskflow/TFJobSystem.h"
|
||||
namespace cc {
|
||||
using JobToken = TFJobToken;
|
||||
using JobGraph = TFJobGraph;
|
||||
using JobSystem = TFJobSystem;
|
||||
} // namespace cc
|
||||
#elif CC_USE_JOB_SYSTEM_TBB
|
||||
#include "job-system-tbb/TBBJobGraph.h"
|
||||
#include "job-system-tbb/TBBJobSystem.h"
|
||||
namespace cc {
|
||||
using JobToken = TBBJobToken;
|
||||
using JobGraph = TBBJobGraph;
|
||||
using JobSystem = TBBJobSystem;
|
||||
} // namespace cc
|
||||
#else
|
||||
#include "job-system-dummy/DummyJobGraph.h"
|
||||
#include "job-system-dummy/DummyJobSystem.h"
|
||||
namespace cc {
|
||||
using JobToken = DummyJobToken;
|
||||
using JobGraph = DummyJobGraph;
|
||||
using JobSystem = DummyJobSystem;
|
||||
} // namespace cc
|
||||
#endif
|
||||
147
cocos/base/job-system/job-system-dummy/DummyJobGraph.cpp
Normal file
147
cocos/base/job-system/job-system-dummy/DummyJobGraph.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "DummyJobGraph.h"
|
||||
#include "base/Macros.h"
|
||||
|
||||
#define DUMMY_GRAPH_NODE_CHUNK_SIZE 64
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
DummyGraphNode *freeList{nullptr};
|
||||
ccstd::vector<DummyGraphNode *> allocatedChunks;
|
||||
} // namespace
|
||||
|
||||
DummyGraphNode::~DummyGraphNode() {
|
||||
delete _callback;
|
||||
}
|
||||
|
||||
void DummyGraphNode::reset() {
|
||||
_successors.clear();
|
||||
_predecessors.clear();
|
||||
delete _callback;
|
||||
_callback = nullptr;
|
||||
}
|
||||
|
||||
void DummyGraphNode::succeed(DummyGraphNode *other) {
|
||||
CC_ASSERT_NE(this, other);
|
||||
// Run after other
|
||||
this->_predecessors.emplace(other);
|
||||
other->_successors.emplace(this);
|
||||
}
|
||||
|
||||
void DummyGraphNode::precede(DummyGraphNode *other) {
|
||||
// Run before other
|
||||
other->succeed(this);
|
||||
}
|
||||
|
||||
void DummyGraphNode::allocChunk() {
|
||||
CC_ASSERT_NULL(freeList);
|
||||
freeList = ccnew DummyGraphNode[DUMMY_GRAPH_NODE_CHUNK_SIZE]();
|
||||
allocatedChunks.emplace_back(freeList);
|
||||
for (auto i = 0; i < DUMMY_GRAPH_NODE_CHUNK_SIZE - 1; i++) {
|
||||
freeList[i]._next = &freeList[i + 1];
|
||||
}
|
||||
freeList[DUMMY_GRAPH_NODE_CHUNK_SIZE - 1]._next = nullptr;
|
||||
}
|
||||
|
||||
DummyGraphNode *DummyGraphNode::alloc() {
|
||||
if (freeList == nullptr) {
|
||||
DummyGraphNode::allocChunk();
|
||||
}
|
||||
auto *p = freeList;
|
||||
freeList = freeList->_next;
|
||||
p->reset();
|
||||
return p;
|
||||
}
|
||||
|
||||
void DummyGraphNode::free(DummyGraphNode *node) {
|
||||
node->_next = freeList;
|
||||
freeList = node;
|
||||
}
|
||||
|
||||
void DummyGraphNode::freeAll() {
|
||||
for (auto *chunk : allocatedChunks) {
|
||||
delete[] chunk;
|
||||
}
|
||||
allocatedChunks.clear();
|
||||
}
|
||||
|
||||
DummyGraph::~DummyGraph() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void DummyGraph::clear() {
|
||||
for (auto *node : _nodes) {
|
||||
DummyGraphNode::free(node);
|
||||
}
|
||||
_nodes.clear();
|
||||
}
|
||||
|
||||
void DummyGraph::link(size_t precede, size_t after) {
|
||||
_nodes[precede]->precede(_nodes[after]);
|
||||
}
|
||||
|
||||
void DummyGraph::run() {
|
||||
for (auto *node : _nodes) {
|
||||
if (!excuted(node)) {
|
||||
walk(node);
|
||||
}
|
||||
}
|
||||
_generation++;
|
||||
}
|
||||
|
||||
void DummyGraph::walk(DummyGraphNode *node) { //NOLINT(misc-no-recursion)
|
||||
for (DummyGraphNode *n : node->_predecessors) {
|
||||
if (!excuted(n)) {
|
||||
walk(n);
|
||||
}
|
||||
}
|
||||
if (!excuted(node)) {
|
||||
node->_callback->execute();
|
||||
node->_generation++;
|
||||
}
|
||||
|
||||
for (DummyGraphNode *n : node->_successors) {
|
||||
if (!excuted(n)) {
|
||||
walk(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DummyGraph::excuted(DummyGraphNode *n) const {
|
||||
return n->_generation != _generation;
|
||||
}
|
||||
|
||||
void DummyJobGraph::makeEdge(uint32_t j1, uint32_t j2) {
|
||||
_dummyGraph.link(j1, j2);
|
||||
}
|
||||
|
||||
void DummyJobGraph::run() noexcept {
|
||||
_dummyGraph.run();
|
||||
_dummyGraph.clear();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
162
cocos/base/job-system/job-system-dummy/DummyJobGraph.h
Normal file
162
cocos/base/job-system/job-system-dummy/DummyJobGraph.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/memory/Memory.h"
|
||||
#include "base/std/container/unordered_set.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class DummyJobSystem;
|
||||
|
||||
class DummyGraphNode;
|
||||
class DummyGraph final {
|
||||
public:
|
||||
DummyGraph() = default;
|
||||
DummyGraph(const DummyGraph &) = delete;
|
||||
DummyGraph(DummyGraph &&) = delete;
|
||||
DummyGraph &operator=(const DummyGraph &) = delete;
|
||||
DummyGraph &operator=(DummyGraph &&) = delete;
|
||||
~DummyGraph();
|
||||
|
||||
template <class Fn>
|
||||
size_t addNode(Fn &&fn);
|
||||
|
||||
void run();
|
||||
void link(size_t precede, size_t after);
|
||||
void walk(DummyGraphNode *node);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
bool excuted(DummyGraphNode *n) const;
|
||||
|
||||
int _generation{0};
|
||||
ccstd::vector<DummyGraphNode *> _nodes;
|
||||
};
|
||||
|
||||
class DummyGraphNodeTaskItf {
|
||||
public:
|
||||
virtual ~DummyGraphNodeTaskItf() = default;
|
||||
virtual void execute() = 0;
|
||||
};
|
||||
|
||||
template <class Fn>
|
||||
class DummyGraphNodeTaskImpl final : public DummyGraphNodeTaskItf {
|
||||
public:
|
||||
explicit DummyGraphNodeTaskImpl(Fn &&t) noexcept;
|
||||
DummyGraphNodeTaskImpl(const DummyGraphNodeTaskImpl &) = delete;
|
||||
DummyGraphNodeTaskImpl(DummyGraphNodeTaskImpl &&) = delete;
|
||||
DummyGraphNodeTaskImpl &operator=(const DummyGraphNodeTaskImpl &) = delete;
|
||||
DummyGraphNodeTaskImpl &operator=(DummyGraphNodeTaskImpl &&) = delete;
|
||||
~DummyGraphNodeTaskImpl() override = default;
|
||||
inline void execute() override { _task(); }
|
||||
|
||||
private:
|
||||
Fn _task;
|
||||
};
|
||||
|
||||
class DummyGraphNode final {
|
||||
public:
|
||||
DummyGraphNode() = default;
|
||||
DummyGraphNode(const DummyGraphNode &) = delete;
|
||||
DummyGraphNode(DummyGraphNode &&) = delete;
|
||||
DummyGraphNode &operator=(const DummyGraphNode &) = delete;
|
||||
DummyGraphNode &operator=(DummyGraphNode &&) = delete;
|
||||
~DummyGraphNode();
|
||||
|
||||
private:
|
||||
static void allocChunk();
|
||||
static DummyGraphNode *alloc();
|
||||
static void free(DummyGraphNode *n);
|
||||
static void freeAll();
|
||||
|
||||
void succeed(DummyGraphNode *other);
|
||||
void precede(DummyGraphNode *other);
|
||||
void reset();
|
||||
|
||||
DummyGraphNodeTaskItf *_callback{nullptr};
|
||||
ccstd::unordered_set<DummyGraphNode *> _successors{};
|
||||
ccstd::unordered_set<DummyGraphNode *> _predecessors{};
|
||||
DummyGraphNode *_next{nullptr};
|
||||
int _generation{0};
|
||||
friend class DummyGraph;
|
||||
};
|
||||
|
||||
template <class Fn>
|
||||
DummyGraphNodeTaskImpl<Fn>::DummyGraphNodeTaskImpl(Fn &&t) noexcept : _task(t) {}
|
||||
|
||||
template <class Fn>
|
||||
size_t DummyGraph::addNode(Fn &&fn) {
|
||||
DummyGraphNode *n = DummyGraphNode::alloc();
|
||||
n->_callback = ccnew DummyGraphNodeTaskImpl<Fn>(std::forward<Fn>(fn));
|
||||
n->_generation = _generation;
|
||||
_nodes.emplace_back(n);
|
||||
return _nodes.size() - 1;
|
||||
}
|
||||
|
||||
// exported declarations
|
||||
|
||||
class DummyJobGraph final {
|
||||
public:
|
||||
explicit DummyJobGraph(DummyJobSystem * /*system*/) noexcept {}
|
||||
DummyJobGraph(const DummyJobGraph &) = delete;
|
||||
DummyJobGraph(DummyJobGraph &&) = delete;
|
||||
DummyJobGraph &operator=(const DummyJobGraph &) = delete;
|
||||
DummyJobGraph &operator=(DummyJobGraph &&) = delete;
|
||||
~DummyJobGraph() noexcept = default;
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createJob(Function &&func) noexcept;
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept;
|
||||
|
||||
void makeEdge(uint32_t j1, uint32_t j2);
|
||||
|
||||
void run() noexcept;
|
||||
|
||||
inline void waitForAll() { run(); }
|
||||
|
||||
private:
|
||||
DummyGraph _dummyGraph{};
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
uint32_t DummyJobGraph::createJob(Function &&func) noexcept {
|
||||
return static_cast<uint32_t>(_dummyGraph.addNode(std::forward<Function>(func)));
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
uint32_t DummyJobGraph::createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept {
|
||||
return static_cast<uint32_t>(_dummyGraph.addNode([callable = std::forward<Function>(func), first = begin, last = end, step = step]() {
|
||||
for (auto i = first; i < last; i += step) {
|
||||
callable(i);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
32
cocos/base/job-system/job-system-dummy/DummyJobSystem.cpp
Normal file
32
cocos/base/job-system/job-system-dummy/DummyJobSystem.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "DummyJobSystem.h"
|
||||
#include "DummyJobGraph.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
DummyJobSystem *DummyJobSystem::instance = nullptr;
|
||||
|
||||
} // namespace cc
|
||||
62
cocos/base/job-system/job-system-dummy/DummyJobSystem.h
Normal file
62
cocos/base/job-system/job-system-dummy/DummyJobSystem.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/Macros.h"
|
||||
#include "base/memory/Memory.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
using DummyJobToken = size_t;
|
||||
|
||||
class DummyJobGraph;
|
||||
|
||||
class DummyJobSystem final {
|
||||
private:
|
||||
static DummyJobSystem *instance;
|
||||
|
||||
public:
|
||||
static DummyJobSystem *getInstance() {
|
||||
if (!instance) {
|
||||
instance = ccnew DummyJobSystem;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void destroyInstance() {
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
DummyJobSystem() noexcept = default;
|
||||
explicit DummyJobSystem(uint32_t /*threadCount*/) noexcept {}
|
||||
|
||||
inline uint32_t threadCount() const { return THREAD_COUNT; } //NOLINT
|
||||
|
||||
private:
|
||||
static constexpr uint32_t THREAD_COUNT = 1U; //always one
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
40
cocos/base/job-system/job-system-taskflow/TFJobGraph.cpp
Normal file
40
cocos/base/job-system/job-system-taskflow/TFJobGraph.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "TFJobGraph.h"
|
||||
#include "TFJobSystem.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
void TFJobGraph::makeEdge(uint32_t j1, uint32_t j2) noexcept {
|
||||
_tasks[j1].precede(_tasks[j2]);
|
||||
}
|
||||
|
||||
void TFJobGraph::run() noexcept {
|
||||
if (_pending) return;
|
||||
_future = _executor->run(_flow);
|
||||
_pending = true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
78
cocos/base/job-system/job-system-taskflow/TFJobGraph.h
Normal file
78
cocos/base/job-system/job-system-taskflow/TFJobGraph.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TFJobSystem.h"
|
||||
#include "base/std/container/deque.h"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
namespace cc {
|
||||
|
||||
using TFJobToken = void;
|
||||
|
||||
class TFJobGraph final {
|
||||
public:
|
||||
explicit TFJobGraph(TFJobSystem *system) noexcept : _executor(&system->_executor) {}
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createJob(Function &&func) noexcept;
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept;
|
||||
|
||||
void makeEdge(uint32_t j1, uint32_t j2) noexcept;
|
||||
|
||||
void run() noexcept;
|
||||
|
||||
inline void waitForAll() {
|
||||
if (_pending) {
|
||||
_future.wait();
|
||||
_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
tf::Executor *_executor = nullptr;
|
||||
|
||||
tf::Taskflow _flow;
|
||||
ccstd::deque<tf::Task> _tasks; // existing tasks cannot be invalidated
|
||||
|
||||
std::future<void> _future;
|
||||
bool _pending = false;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
uint32_t TFJobGraph::createJob(Function &&func) noexcept {
|
||||
_tasks.emplace_back(_flow.emplace(func));
|
||||
return static_cast<uint32_t>(_tasks.size() - 1u);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
uint32_t TFJobGraph::createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept {
|
||||
_tasks.emplace_back(_flow.for_each_index(begin, end, step, func));
|
||||
return static_cast<uint32_t>(_tasks.size() - 1u);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
38
cocos/base/job-system/job-system-taskflow/TFJobSystem.cpp
Normal file
38
cocos/base/job-system/job-system-taskflow/TFJobSystem.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "TFJobSystem.h"
|
||||
#include "TFJobGraph.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
TFJobSystem *TFJobSystem::_instance = nullptr;
|
||||
|
||||
TFJobSystem::TFJobSystem(uint32_t threadCount) noexcept
|
||||
: _executor(threadCount) {
|
||||
CC_LOG_INFO("Taskflow Job system initialized: %d worker threads", threadCount);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
60
cocos/base/job-system/job-system-taskflow/TFJobSystem.h
Normal file
60
cocos/base/job-system/job-system-taskflow/TFJobSystem.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include "base/memory/Memory.h"
|
||||
#include "taskflow/taskflow.hpp"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class TFJobSystem final {
|
||||
public:
|
||||
static TFJobSystem *getInstance() {
|
||||
if (!_instance) {
|
||||
_instance = ccnew TFJobSystem;
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static void destroyInstance() {
|
||||
CC_SAFE_DELETE(_instance);
|
||||
}
|
||||
|
||||
TFJobSystem() noexcept : TFJobSystem(std::max(2u, std::thread::hardware_concurrency() - 2u)) {}
|
||||
explicit TFJobSystem(uint32_t threadCount) noexcept;
|
||||
|
||||
inline uint32_t threadCount() { return static_cast<uint32_t>(_executor.num_workers()); }
|
||||
|
||||
private:
|
||||
friend class TFJobGraph;
|
||||
|
||||
static TFJobSystem *_instance;
|
||||
|
||||
tf::Executor _executor;
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
46
cocos/base/job-system/job-system-tbb/TBBJobGraph.cpp
Normal file
46
cocos/base/job-system/job-system-tbb/TBBJobGraph.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "TBBJobGraph.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
void TBBJobGraph::makeEdge(uint32_t j1, uint32_t j2) noexcept {
|
||||
if (j1 & PARALLEL_JOB_FLAG) {
|
||||
j1 = _parallelJobs[j1 & PARALLEL_JOB_MASK].successor;
|
||||
}
|
||||
|
||||
if (j2 & PARALLEL_JOB_FLAG) {
|
||||
j2 = _parallelJobs[j2 & PARALLEL_JOB_MASK].predecessor;
|
||||
}
|
||||
|
||||
tbb::flow::make_edge(_nodes[j1], _nodes[j2]);
|
||||
}
|
||||
|
||||
void TBBJobGraph::run() noexcept {
|
||||
_nodes.front().try_put(tbb::flow::continue_msg());
|
||||
_pending = true;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
107
cocos/base/job-system/job-system-tbb/TBBJobGraph.h
Normal file
107
cocos/base/job-system/job-system-tbb/TBBJobGraph.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tbb/flow_graph.h>
|
||||
#include "base/std/container/deque.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
using TBBJobToken = tbb::flow::continue_msg;
|
||||
|
||||
class TBBJobSystem;
|
||||
|
||||
class TBBJobGraph final {
|
||||
public:
|
||||
explicit TBBJobGraph(TBBJobSystem *system) noexcept {
|
||||
_nodes.emplace_back(_graph, [](TBBJobToken t) {});
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createJob(Function &&func) noexcept;
|
||||
|
||||
template <typename Function>
|
||||
uint32_t createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept;
|
||||
|
||||
void makeEdge(uint32_t j1, uint32_t j2) noexcept;
|
||||
|
||||
void run() noexcept;
|
||||
|
||||
inline void waitForAll() {
|
||||
if (_pending) {
|
||||
_graph.wait_for_all();
|
||||
_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr uint32_t PARALLEL_JOB_FLAG = 1u << 20;
|
||||
static constexpr uint32_t PARALLEL_JOB_MASK = ~PARALLEL_JOB_FLAG;
|
||||
|
||||
tbb::flow::graph _graph;
|
||||
|
||||
using TBBJobNode = tbb::flow::continue_node<tbb::flow::continue_msg>;
|
||||
ccstd::deque<TBBJobNode> _nodes; // existing nodes cannot be invalidated
|
||||
|
||||
struct TBBParallelJob {
|
||||
uint32_t predecessor = 0u;
|
||||
uint32_t successor = 0u;
|
||||
};
|
||||
ccstd::vector<TBBParallelJob> _parallelJobs;
|
||||
|
||||
bool _pending = false;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
uint32_t TBBJobGraph::createJob(Function &&func) noexcept {
|
||||
_nodes.emplace_back(_graph, func);
|
||||
tbb::flow::make_edge(_nodes.front(), _nodes.back());
|
||||
return static_cast<uint32_t>(_nodes.size() - 1u);
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
uint32_t TBBJobGraph::createForEachIndexJob(uint32_t begin, uint32_t end, uint32_t step, Function &&func) noexcept {
|
||||
_nodes.emplace_back(_graph, [](TBBJobToken t) {});
|
||||
auto predecessorIdx = static_cast<uint32_t>(_nodes.size() - 1u);
|
||||
TBBJobNode &predecessor = _nodes.back();
|
||||
|
||||
tbb::flow::make_edge(_nodes.front(), predecessor);
|
||||
|
||||
_nodes.emplace_back(_graph, [](TBBJobToken t) {});
|
||||
auto successorIdx = static_cast<uint32_t>(_nodes.size() - 1u);
|
||||
TBBJobNode &successor = _nodes.back();
|
||||
|
||||
for (uint32_t i = begin; i < end; i += step) {
|
||||
_nodes.emplace_back(_graph, [i, &func](TBBJobToken t) { func(i); });
|
||||
tbb::flow::make_edge(predecessor, _nodes.back());
|
||||
tbb::flow::make_edge(_nodes.back(), successor);
|
||||
}
|
||||
|
||||
_parallelJobs.push_back({predecessorIdx, successorIdx});
|
||||
return static_cast<uint32_t>((_parallelJobs.size() - 1u)) | PARALLEL_JOB_FLAG;
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
40
cocos/base/job-system/job-system-tbb/TBBJobSystem.cpp
Normal file
40
cocos/base/job-system/job-system-tbb/TBBJobSystem.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "base/Log.h"
|
||||
|
||||
#include "TBBJobGraph.h"
|
||||
#include "TBBJobSystem.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
TBBJobSystem *TBBJobSystem::_instance = nullptr;
|
||||
|
||||
TBBJobSystem::TBBJobSystem(uint32_t threadCount) noexcept
|
||||
: _control(tbb::global_control::max_allowed_parallelism, threadCount),
|
||||
_threadCount(threadCount) {
|
||||
CC_LOG_INFO("TBB Job system initialized: %d worker threads", threadCount);
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
61
cocos/base/job-system/job-system-tbb/TBBJobSystem.h
Normal file
61
cocos/base/job-system/job-system-tbb/TBBJobSystem.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include "base/memory/Memory.h"
|
||||
#include "tbb/global_control.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
class TBBJobGraph;
|
||||
|
||||
class TBBJobSystem final {
|
||||
public:
|
||||
static TBBJobSystem *getInstance() {
|
||||
if (!_instance) {
|
||||
_instance = ccnew TBBJobSystem;
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static void destroyInstance() {
|
||||
CC_SAFE_DELETE(_instance);
|
||||
}
|
||||
|
||||
TBBJobSystem() noexcept : TBBJobSystem(std::max(2u, std::thread::hardware_concurrency() - 2u)) {}
|
||||
explicit TBBJobSystem(uint32_t threadCount) noexcept;
|
||||
|
||||
inline uint32_t threadCount() { return _threadCount; }
|
||||
|
||||
private:
|
||||
static TBBJobSystem *_instance;
|
||||
|
||||
tbb::global_control _control;
|
||||
uint32_t _threadCount{0u};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
300
cocos/base/memory/CallStack.cpp
Normal file
300
cocos/base/memory/CallStack.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "CallStack.h"
|
||||
#if USE_MEMORY_LEAK_DETECTOR
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#define __GNU_SOURCE
|
||||
#include <cxxabi.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
#include <execinfo.h>
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
#include <DbgHelp.h>
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
#endif
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace cc {
|
||||
|
||||
ccstd::string StackFrame::toString() {
|
||||
static ccstd::string unknown("unknown");
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
std::stringstream stream;
|
||||
stream << "\tmodule: " << (module.empty() ? unknown : module)
|
||||
<< "\tfunction: " << (function.empty() ? unknown : function);
|
||||
|
||||
return stream.str();
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
std::stringstream stream;
|
||||
stream << "\tfile: " << (file.empty() ? unknown : file);
|
||||
|
||||
return stream.str();
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
std::stringstream stream;
|
||||
stream << "\tmodule: " << (module.empty() ? unknown : module)
|
||||
<< "\tfile: " << (file.empty() ? unknown : file)
|
||||
<< "\tfunction: " << (function.empty() ? unknown : function)
|
||||
<< "\tline: " << line;
|
||||
|
||||
return stream.str();
|
||||
|
||||
#else
|
||||
return unknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
|
||||
struct ThreadStack {
|
||||
void *stack[MAX_STACK_FRAMES];
|
||||
int current;
|
||||
int overflow;
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
static pthread_once_t s_once = PTHREAD_ONCE_INIT;
|
||||
static pthread_key_t s_threadStackKey = 0;
|
||||
|
||||
static void __attribute__((no_instrument_function))
|
||||
init_once(void) {
|
||||
pthread_key_create(&s_threadStackKey, NULL);
|
||||
}
|
||||
|
||||
static ThreadStack *__attribute__((no_instrument_function))
|
||||
getThreadStack() {
|
||||
ThreadStack *ptr = (ThreadStack *)pthread_getspecific(s_threadStackKey);
|
||||
if (ptr) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ptr = (ThreadStack *)calloc(1, sizeof(ThreadStack));
|
||||
ptr->current = 0;
|
||||
ptr->overflow = 0;
|
||||
pthread_setspecific(s_threadStackKey, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void __attribute__((no_instrument_function))
|
||||
__cyg_profile_func_enter(void *this_fn, void *call_site) {
|
||||
pthread_once(&s_once, init_once);
|
||||
ThreadStack *ptr = getThreadStack();
|
||||
if (ptr->current < MAX_STACK_FRAMES) {
|
||||
ptr->stack[ptr->current++] = this_fn;
|
||||
ptr->overflow = 0;
|
||||
} else {
|
||||
ptr->overflow++;
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((no_instrument_function))
|
||||
__cyg_profile_func_exit(void *this_fn, void *call_site) {
|
||||
pthread_once(&s_once, init_once);
|
||||
ThreadStack *ptr = getThreadStack();
|
||||
|
||||
if (ptr->overflow == 0 && ptr->current > 0) {
|
||||
ptr->current--;
|
||||
}
|
||||
|
||||
if (ptr->overflow > 0) {
|
||||
ptr->overflow--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ccstd::string CallStack::basename(const ccstd::string &path) {
|
||||
size_t found = path.find_last_of("/\\");
|
||||
|
||||
if (ccstd::string::npos != found) {
|
||||
return path.substr(found + 1);
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
ccstd::vector<void *> CallStack::backtrace() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
ccstd::vector<void *> callstack;
|
||||
callstack.reserve(MAX_STACK_FRAMES);
|
||||
|
||||
pthread_once(&s_once, init_once);
|
||||
ThreadStack *ptr = getThreadStack();
|
||||
for (int i = ptr->current - 1; i >= 0; i--) {
|
||||
callstack.push_back(ptr->stack[i]);
|
||||
}
|
||||
|
||||
return callstack;
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
ccstd::vector<void *> callstack;
|
||||
callstack.reserve(MAX_STACK_FRAMES);
|
||||
|
||||
void *array[MAX_STACK_FRAMES];
|
||||
int count = ::backtrace(array, MAX_STACK_FRAMES);
|
||||
for (auto i = 0; i < count; i++) {
|
||||
callstack.push_back(array[i]);
|
||||
}
|
||||
return callstack;
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
ccstd::vector<void *> callstack;
|
||||
callstack.reserve(MAX_STACK_FRAMES);
|
||||
|
||||
void *array[MAX_STACK_FRAMES];
|
||||
int count = CaptureStackBackTrace(0, MAX_STACK_FRAMES, array, NULL);
|
||||
for (auto i = 0; i < count; i++) {
|
||||
callstack.push_back(array[i]);
|
||||
}
|
||||
return callstack;
|
||||
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
ccstd::vector<StackFrame> CallStack::backtraceSymbols(const ccstd::vector<void *> &callstack) {
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
ccstd::vector<StackFrame> frames;
|
||||
size_t size = callstack.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
Dl_info info;
|
||||
StackFrame frame;
|
||||
if (dladdr(callstack[i], &info)) {
|
||||
if (info.dli_fname && strlen(info.dli_fname) > 0) {
|
||||
frame.module = basename(info.dli_fname);
|
||||
}
|
||||
|
||||
if (info.dli_sname && strlen(info.dli_sname) > 0) {
|
||||
char *real_name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, nullptr);
|
||||
if (real_name) {
|
||||
frame.function = real_name;
|
||||
free(real_name);
|
||||
} else {
|
||||
frame.function = info.dli_sname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frames.push_back(std::move(frame));
|
||||
}
|
||||
return frames;
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
size_t size = callstack.size();
|
||||
if (size == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
ccstd::vector<StackFrame> frames;
|
||||
char **strs = ::backtrace_symbols(&callstack[0], size);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
StackFrame frame;
|
||||
frame.file = strs[i];
|
||||
frames.push_back(std::move(frame));
|
||||
}
|
||||
|
||||
return frames;
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
ccstd::vector<StackFrame> frames;
|
||||
|
||||
#if _WIN64
|
||||
using PTR_DWORD = DWORD64;
|
||||
#else
|
||||
using PTR_DWORD = DWORD;
|
||||
#endif
|
||||
|
||||
size_t size = callstack.size();
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
StackFrame frame;
|
||||
PTR_DWORD address = reinterpret_cast<PTR_DWORD>(callstack[i]);
|
||||
|
||||
char moduelName[MAX_PATH];
|
||||
#if _WIN64
|
||||
PTR_DWORD moduleBase = SymGetModuleBase64(_process, address);
|
||||
#else
|
||||
PTR_DWORD moduleBase = SymGetModuleBase(_process, address);
|
||||
#endif
|
||||
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, moduelName, MAX_PATH)) {
|
||||
frame.module = basename(moduelName);
|
||||
}
|
||||
|
||||
DWORD64 offset = 0;
|
||||
char symbolBuffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_LENGTH] = {0};
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbolBuffer;
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYMBOL_LENGTH - 1;
|
||||
|
||||
if (SymFromAddr(_process, address, &offset, symbol)) {
|
||||
frame.function = symbol->Name;
|
||||
}
|
||||
|
||||
IMAGEHLP_LINE line;
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
|
||||
DWORD offset_ln = 0;
|
||||
|
||||
if (SymGetLineFromAddr(_process, address, &offset_ln, &line)) {
|
||||
frame.file = line.FileName;
|
||||
frame.line = line.LineNumber;
|
||||
}
|
||||
|
||||
frames.push_back(std::move(frame));
|
||||
}
|
||||
|
||||
return frames;
|
||||
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
void CallStack::initSym() {
|
||||
_process = GetCurrentProcess();
|
||||
if (SymInitialize(_process, nullptr, true) == false) {
|
||||
CC_ABORT();
|
||||
}
|
||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||
}
|
||||
|
||||
void CallStack::cleanupSym() {
|
||||
SymCleanup(_process);
|
||||
}
|
||||
|
||||
HANDLE CallStack::_process = 0;
|
||||
#endif
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#endif
|
||||
76
cocos/base/memory/CallStack.h
Normal file
76
cocos/base/memory/CallStack.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Config.h"
|
||||
#if USE_MEMORY_LEAK_DETECTOR
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
#include "../Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
#define MAX_STACK_FRAMES 64
|
||||
#define MAX_SYMBOL_LENGTH 255
|
||||
|
||||
/**
|
||||
* A single frame of callstack.
|
||||
*/
|
||||
struct CC_DLL StackFrame {
|
||||
ccstd::string module;
|
||||
ccstd::string file;
|
||||
ccstd::string function;
|
||||
uint32_t line{0};
|
||||
|
||||
ccstd::string toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* An utility class used to backtrace callstack.
|
||||
*/
|
||||
class CC_DLL CallStack {
|
||||
public:
|
||||
static ccstd::string basename(const ccstd::string &path);
|
||||
|
||||
static ccstd::vector<void *> backtrace();
|
||||
static ccstd::vector<StackFrame> backtraceSymbols(const ccstd::vector<void *> &callstack);
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
static void initSym();
|
||||
static void cleanupSym();
|
||||
|
||||
private:
|
||||
static HANDLE _process;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#endif
|
||||
131
cocos/base/memory/Memory.h
Normal file
131
cocos/base/memory/Memory.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if (CC_PLATFORM == CC_PLATFORM_IOS)
|
||||
#include <Availability.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include <new> // std::nothrow
|
||||
|
||||
#include "base/Macros.h"
|
||||
|
||||
namespace cc {
|
||||
class MemoryAllocDealloc final {
|
||||
public:
|
||||
inline static void *allocateBytesAligned(size_t alignment, size_t count) {
|
||||
#ifdef _MSC_VER
|
||||
void *ptr = _aligned_malloc(count, alignment);
|
||||
#else
|
||||
// alignment is not multiple of sizeof(void*)
|
||||
CC_ASSERT_ZERO(alignment % sizeof(void *));
|
||||
void *ptr = nullptr;
|
||||
posix_memalign(&ptr, alignment, count);
|
||||
#endif
|
||||
return ptr;
|
||||
}
|
||||
|
||||
inline static void deallocateBytesAligned(void *ptr) {
|
||||
#ifdef _MSC_VER
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace cc
|
||||
|
||||
#define ccnew new (std::nothrow) //NOLINT(readability-identifier-naming)
|
||||
#define ccnew_placement(...) new (__VA_ARGS__) //NOLINT(readability-identifier-naming)
|
||||
|
||||
#define CC_SAFE_DELETE(ptr) \
|
||||
if (ptr) { \
|
||||
delete ptr; \
|
||||
(ptr) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_SAFE_DELETE_ARRAY(ptr) \
|
||||
if (ptr) { \
|
||||
delete[] ptr; \
|
||||
(ptr) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_MALLOC(bytes) malloc(bytes)
|
||||
#define CC_MALLOC_ALIGN(bytes, align) ::cc::MemoryAllocDealloc::allocateBytesAligned(align, bytes)
|
||||
#define CC_REALLOC(ptr, bytes) realloc(ptr, bytes)
|
||||
#define CC_FREE(ptr) free((void *)ptr)
|
||||
#define CC_FREE_ALIGN(ptr) ::cc::MemoryAllocDealloc::deallocateBytesAligned(ptr)
|
||||
|
||||
#define CC_SAFE_FREE(ptr) \
|
||||
if (ptr) { \
|
||||
CC_FREE(ptr); \
|
||||
(ptr) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_SAFE_DESTROY(ptr) \
|
||||
if (ptr) { \
|
||||
(ptr)->destroy(); \
|
||||
}
|
||||
|
||||
#define CC_SAFE_DESTROY_AND_DELETE(ptr) \
|
||||
if (ptr) { \
|
||||
(ptr)->destroy(); \
|
||||
delete ptr; \
|
||||
(ptr) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_SAFE_DESTROY_NULL(ptr) \
|
||||
if (ptr) { \
|
||||
(ptr)->destroy(); \
|
||||
(ptr) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_SAFE_RELEASE(p) \
|
||||
if (p) { \
|
||||
(p)->release(); \
|
||||
}
|
||||
|
||||
#define CC_SAFE_RELEASE_NULL(p) \
|
||||
if (p) { \
|
||||
(p)->release(); \
|
||||
(p) = nullptr; \
|
||||
}
|
||||
|
||||
#define CC_SAFE_ADD_REF(p) \
|
||||
if (p) { \
|
||||
(p)->addRef(); \
|
||||
}
|
||||
|
||||
#if ((CC_PLATFORM == CC_PLATFORM_IOS) && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_11_0)) || SWIGCOCOS
|
||||
#define ALIGNAS(x)
|
||||
#else
|
||||
#define ALIGNAS(x) alignas(x)
|
||||
#endif
|
||||
338
cocos/base/memory/MemoryHook.cpp
Normal file
338
cocos/base/memory/MemoryHook.cpp
Normal file
@@ -0,0 +1,338 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "MemoryHook.h"
|
||||
#include "CallStack.h"
|
||||
#if USE_MEMORY_LEAK_DETECTOR
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#define __GNU_SOURCE
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
static NewHookType g_new_hooker = nullptr;
|
||||
static DeleteHookType g_delete_hooker = nullptr;
|
||||
|
||||
extern "C" {
|
||||
|
||||
void *malloc(size_t size) __attribute__((weak));
|
||||
void free(void *ptr) __attribute__((weak));
|
||||
|
||||
// Use strong symbol to overwrite the weak one.
|
||||
void *malloc(size_t size) {
|
||||
static MallocType system_malloc = nullptr;
|
||||
if (CC_PREDICT_FALSE(system_malloc == nullptr)) {
|
||||
system_malloc = (MallocType)dlsym(RTLD_NEXT, "malloc");
|
||||
}
|
||||
|
||||
void *ptr = system_malloc(size);
|
||||
if (CC_PREDICT_TRUE(g_new_hooker != nullptr)) {
|
||||
g_new_hooker(ptr, size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
static FreeType system_free = nullptr;
|
||||
if (CC_PREDICT_FALSE(system_free == nullptr)) {
|
||||
system_free = (FreeType)dlsym(RTLD_NEXT, "free");
|
||||
}
|
||||
|
||||
system_free(ptr);
|
||||
if (CC_PREDICT_TRUE(g_delete_hooker != nullptr)) {
|
||||
g_delete_hooker(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
typedef void malloc_logger_t(uint32_t aType,
|
||||
uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
|
||||
uintptr_t aResult, uint32_t aNumHotFramesToSkip);
|
||||
|
||||
extern malloc_logger_t *malloc_logger;
|
||||
static malloc_logger_t *g_system_malloc_logger = nullptr;
|
||||
static NewHookType g_new_hooker = nullptr;
|
||||
static DeleteHookType g_delete_hooker = nullptr;
|
||||
|
||||
static void
|
||||
cc_malloc_logger(uint32_t aType,
|
||||
uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
|
||||
uintptr_t aResult, uint32_t aNumHotFramesToSkip) {
|
||||
if (aResult != 0) {
|
||||
size_t new_size = reinterpret_cast<size_t>(aArg3);
|
||||
if (new_size != 0) {
|
||||
// realloc
|
||||
if (CC_PREDICT_TRUE(g_delete_hooker != nullptr)) {
|
||||
const void *ptr = reinterpret_cast<const void *>(aArg2);
|
||||
g_delete_hooker(ptr);
|
||||
}
|
||||
|
||||
if (CC_PREDICT_TRUE(g_new_hooker != nullptr)) {
|
||||
const void *new_ptr = reinterpret_cast<const void *>(aResult);
|
||||
g_new_hooker(new_ptr, new_size);
|
||||
}
|
||||
} else {
|
||||
// malloc/calloc/valloc
|
||||
if (CC_PREDICT_TRUE(g_new_hooker != nullptr)) {
|
||||
const void *ptr = reinterpret_cast<const void *>(aResult);
|
||||
size_t size = reinterpret_cast<size_t>(aArg2);
|
||||
g_new_hooker(ptr, size);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// free
|
||||
if (CC_PREDICT_TRUE(g_delete_hooker != nullptr)) {
|
||||
const void *ptr = reinterpret_cast<const void *>(aArg2);
|
||||
g_delete_hooker(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
#include <Windows.h>
|
||||
|
||||
extern "C" {
|
||||
typedef void (*MallocHook_NewHook)(const void *ptr, size_t size);
|
||||
typedef void (*MallocHook_DeleteHook)(const void *ptr);
|
||||
|
||||
int MallocHook_AddNewHook(MallocHook_NewHook hook);
|
||||
int MallocHook_RemoveNewHook(MallocHook_NewHook hook);
|
||||
int MallocHook_AddDeleteHook(MallocHook_DeleteHook hook);
|
||||
int MallocHook_RemoveDeleteHook(MallocHook_DeleteHook hook);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace cc {
|
||||
|
||||
static void newHook(const void *ptr, size_t size) {
|
||||
uint64_t address = reinterpret_cast<uint64_t>(ptr);
|
||||
GMemoryHook.addRecord(address, size);
|
||||
}
|
||||
|
||||
static void deleteHook(const void *ptr) {
|
||||
uint64_t address = reinterpret_cast<uint64_t>(ptr);
|
||||
GMemoryHook.removeRecord(address);
|
||||
}
|
||||
|
||||
MemoryHook::MemoryHook() {
|
||||
registerAll();
|
||||
}
|
||||
|
||||
MemoryHook::~MemoryHook() {
|
||||
unRegisterAll();
|
||||
dumpMemoryLeak();
|
||||
}
|
||||
|
||||
void MemoryHook::addRecord(uint64_t address, size_t size) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
if (_hooking) {
|
||||
return;
|
||||
}
|
||||
|
||||
_hooking = true;
|
||||
|
||||
// {} is necessary here to make variables being destroyed before _hooking = false
|
||||
{
|
||||
MemoryRecord record;
|
||||
record.address = address;
|
||||
record.size = size;
|
||||
record.callstack = CallStack::backtrace();
|
||||
_records.insert({address, record});
|
||||
_totalSize += size;
|
||||
}
|
||||
|
||||
_hooking = false;
|
||||
}
|
||||
|
||||
void MemoryHook::removeRecord(uint64_t address) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
if (_hooking) {
|
||||
return;
|
||||
}
|
||||
|
||||
_hooking = true;
|
||||
|
||||
// {} is necessary here to make variables being destroyed before _hooking = false
|
||||
{
|
||||
auto iter = _records.find(address);
|
||||
if (iter != _records.end()) {
|
||||
_totalSize -= iter->second.size;
|
||||
_records.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
_hooking = false;
|
||||
}
|
||||
|
||||
static bool isIgnored(const StackFrame &frame) {
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
static const ccstd::vector<ccstd::string> ignoreModules = {
|
||||
"SDL2",
|
||||
"EGL",
|
||||
"GLESv2",
|
||||
"opengl32",
|
||||
"nvoglv64",
|
||||
"sqlite3",
|
||||
"libuv",
|
||||
"SogouPy"};
|
||||
|
||||
static const ccstd::vector<ccstd::string> ignoreFunctions = {
|
||||
"type_info::name"};
|
||||
|
||||
for (auto &module : ignoreModules) {
|
||||
if (frame.module.find(module) != ccstd::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &function : ignoreFunctions) {
|
||||
if (frame.function.find(function) != ccstd::string::npos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHook::dumpMemoryLeak() {
|
||||
std::lock_guard<std::recursive_mutex> lock(_mutex);
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
CallStack::initSym();
|
||||
#endif
|
||||
|
||||
std::stringstream startStream;
|
||||
startStream << std::endl;
|
||||
startStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
startStream << "--------------------------------------memory leak report start-------------------------------------------" << std::endl;
|
||||
startStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
log(startStream.str());
|
||||
|
||||
if (_records.size() == 0) {
|
||||
std::stringstream stream;
|
||||
stream << std::endl;
|
||||
stream << "Congratulations! There is no memory leak at all." << std::endl;
|
||||
log(stream.str());
|
||||
}
|
||||
|
||||
uint32_t i = 0;
|
||||
size_t skipSize = 0;
|
||||
uint32_t skipCount = 0;
|
||||
|
||||
for (const auto &iter : _records) {
|
||||
bool skip = false;
|
||||
auto frames = CallStack::backtraceSymbols(iter.second.callstack);
|
||||
for (auto &frame : frames) {
|
||||
if (isIgnored(frame)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
skipSize += iter.second.size;
|
||||
skipCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::stringstream stream;
|
||||
int k = 0;
|
||||
|
||||
stream << std::endl;
|
||||
stream << "<" << ++i << ">:"
|
||||
<< "leak " << iter.second.size << " bytes at 0x" << std::hex << iter.second.address << std::dec << std::endl;
|
||||
stream << "\tcallstack:" << std::endl;
|
||||
|
||||
for (auto &frame : frames) {
|
||||
stream << "\t[" << ++k << "]:" << frame.toString() << std::endl;
|
||||
}
|
||||
|
||||
log(stream.str());
|
||||
}
|
||||
|
||||
std::stringstream endStream;
|
||||
endStream << std::endl
|
||||
<< "Total leak count: " << _records.size() << " with " << _totalSize << " bytes, "
|
||||
<< "Total skip count: " << skipCount << " with " << skipSize << " bytes" << std::endl;
|
||||
|
||||
endStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
endStream << "--------------------------------------memory leak report end---------------------------------------------" << std::endl;
|
||||
endStream << "---------------------------------------------------------------------------------------------------------" << std::endl;
|
||||
log(endStream.str());
|
||||
|
||||
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
CallStack::cleanupSym();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHook::log(const ccstd::string &msg) {
|
||||
#if (CC_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
__android_log_write(ANDROID_LOG_WARN, "Cocos", msg.c_str());
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
fputs(msg.c_str(), stdout);
|
||||
#elif (CC_PLATFORM == CC_PLATFORM_WINDOWS)
|
||||
OutputDebugStringA(msg.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHook::registerAll() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
g_new_hooker = newHook;
|
||||
g_delete_hooker = deleteHook;
|
||||
free(malloc(1)); // force to init system_malloc/system_free
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
g_system_malloc_logger = malloc_logger;
|
||||
malloc_logger = cc_malloc_logger;
|
||||
g_new_hooker = newHook;
|
||||
g_delete_hooker = deleteHook;
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
MallocHook_AddNewHook(&newHook);
|
||||
MallocHook_AddDeleteHook(&deleteHook);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemoryHook::unRegisterAll() {
|
||||
#if CC_PLATFORM == CC_PLATFORM_ANDROID
|
||||
g_new_hooker = nullptr;
|
||||
g_delete_hooker = nullptr;
|
||||
#elif CC_PLATFORM == CC_PLATFORM_IOS || CC_PLATFORM == CC_PLATFORM_MACOS
|
||||
malloc_logger = g_system_malloc_logger;
|
||||
g_new_hooker = nullptr;
|
||||
g_delete_hooker = nullptr;
|
||||
#elif CC_PLATFORM == CC_PLATFORM_WINDOWS
|
||||
MallocHook_RemoveNewHook(&newHook);
|
||||
MallocHook_RemoveDeleteHook(&deleteHook);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#endif
|
||||
93
cocos/base/memory/MemoryHook.h
Normal file
93
cocos/base/memory/MemoryHook.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Config.h"
|
||||
#if USE_MEMORY_LEAK_DETECTOR
|
||||
|
||||
#include <mutex>
|
||||
#include "../Macros.h"
|
||||
#include "base/std/container/string.h"
|
||||
#include "base/std/container/unordered_map.h"
|
||||
#include "base/std/container/vector.h"
|
||||
|
||||
typedef void *(*MallocType)(size_t size);
|
||||
typedef void (*FreeType)(void *ptr);
|
||||
|
||||
typedef void (*NewHookType)(const void *ptr, size_t size);
|
||||
typedef void (*DeleteHookType)(const void *ptr);
|
||||
|
||||
namespace cc {
|
||||
|
||||
struct CC_DLL MemoryRecord {
|
||||
uint64_t address{0};
|
||||
size_t size{0};
|
||||
ccstd::vector<void *> callstack;
|
||||
};
|
||||
|
||||
class CC_DLL MemoryHook {
|
||||
public:
|
||||
MemoryHook();
|
||||
~MemoryHook();
|
||||
|
||||
/**
|
||||
* RecordMap's key is memory address.
|
||||
*/
|
||||
using RecordMap = ccstd::unordered_map<uint64_t, MemoryRecord>;
|
||||
|
||||
void addRecord(uint64_t address, size_t size);
|
||||
void removeRecord(uint64_t address);
|
||||
inline size_t getTotalSize() const { return _totalSize; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Dump all memory leaks to output window
|
||||
*/
|
||||
void dumpMemoryLeak();
|
||||
|
||||
static void log(const ccstd::string &msg);
|
||||
|
||||
/**
|
||||
* Register all malloc hooks
|
||||
*/
|
||||
void registerAll();
|
||||
|
||||
/**
|
||||
* Unregister all malloc hooks
|
||||
*/
|
||||
void unRegisterAll();
|
||||
|
||||
private:
|
||||
std::recursive_mutex _mutex;
|
||||
bool _hooking{false};
|
||||
RecordMap _records;
|
||||
size_t _totalSize{0U};
|
||||
};
|
||||
|
||||
extern MemoryHook GMemoryHook;
|
||||
|
||||
} // namespace cc
|
||||
|
||||
#endif
|
||||
79
cocos/base/std/any.h
Normal file
79
cocos/base/std/any.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_CXX_17
|
||||
|
||||
#include <any>
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
using std::any;
|
||||
using std::any_cast;
|
||||
|
||||
} // namespace ccstd
|
||||
|
||||
#else
|
||||
|
||||
#include "boost/any.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
class any : public boost::any { // NOLINT // use std style
|
||||
public:
|
||||
using boost::any::any;
|
||||
|
||||
inline bool has_value() const noexcept { // NOLINT // use std style
|
||||
return !this->empty();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
inline ValueType *any_cast(any *operand) noexcept { // NOLINT // use std style
|
||||
return boost::any_cast<ValueType>(operand);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline const ValueType *any_cast(const any *operand) noexcept { // NOLINT // use std style
|
||||
return boost::any_cast<ValueType>(operand);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline ValueType any_cast(any &operand) { // NOLINT // use std style
|
||||
return boost::any_cast<ValueType>(operand);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline ValueType any_cast(const any &operand) { // NOLINT // use std style
|
||||
return boost::any_cast<ValueType>(operand);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
inline ValueType any_cast(any &&operand) { // NOLINT // use std style
|
||||
return boost::any_cast<ValueType>(operand);
|
||||
}
|
||||
|
||||
} // namespace ccstd
|
||||
#endif
|
||||
31
cocos/base/std/container/array.h
Normal file
31
cocos/base/std/container/array.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace ccstd {
|
||||
using std::array;
|
||||
} // namespace ccstd
|
||||
37
cocos/base/std/container/deque.h
Normal file
37
cocos/base/std/container/deque.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::deque;
|
||||
|
||||
namespace pmr {
|
||||
template <class T>
|
||||
using deque = std::deque<T, boost::container::pmr::polymorphic_allocator<T>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
37
cocos/base/std/container/list.h
Normal file
37
cocos/base/std/container/list.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::list;
|
||||
|
||||
namespace pmr {
|
||||
template <class T>
|
||||
using list = std::list<T, boost::container::pmr::polymorphic_allocator<T>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
38
cocos/base/std/container/map.h
Normal file
38
cocos/base/std/container/map.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::map;
|
||||
|
||||
namespace pmr {
|
||||
template <class Key, class T, class Compare = std::less<Key>>
|
||||
using map = std::map<Key, T, Compare, boost::container::pmr::polymorphic_allocator<std::pair<const Key, T>>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
37
cocos/base/std/container/queue.h
Normal file
37
cocos/base/std/container/queue.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::queue;
|
||||
|
||||
namespace pmr {
|
||||
template <class T>
|
||||
using queue = std::queue<T, boost::container::pmr::polymorphic_allocator<T>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
39
cocos/base/std/container/set.h
Normal file
39
cocos/base/std/container/set.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::set;
|
||||
|
||||
namespace pmr {
|
||||
template <
|
||||
class Key,
|
||||
class Compare = std::less<Key>>
|
||||
using set = std::set<Key, Compare, boost::container::pmr::polymorphic_allocator<Key>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
36
cocos/base/std/container/string.h
Normal file
36
cocos/base/std/container/string.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::string;
|
||||
|
||||
namespace pmr {
|
||||
using string = std::basic_string<char, std::char_traits<char>, boost::container::pmr::polymorphic_allocator<char>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
51
cocos/base/std/container/unordered_map.h
Normal file
51
cocos/base/std/container/unordered_map.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include "base/std/hash/hash_fwd.hpp"
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::unordered_map;
|
||||
using std::unordered_multimap;
|
||||
|
||||
namespace pmr {
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Hash = ccstd::hash<Key>,
|
||||
class Pred = std::equal_to<Key>>
|
||||
using unordered_map = std::unordered_map<Key, T, Hash, Pred, boost::container::pmr::polymorphic_allocator<std::pair<const Key, T>>>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class T,
|
||||
class Hash = ccstd::hash<Key>,
|
||||
class Pred = std::equal_to<Key>>
|
||||
using unordered_multimap = std::unordered_multimap<Key, T, Hash, Pred, boost::container::pmr::polymorphic_allocator<std::pair<const Key, T>>>;
|
||||
} // namespace pmr
|
||||
} // namespace ccstd
|
||||
40
cocos/base/std/container/unordered_set.h
Normal file
40
cocos/base/std/container/unordered_set.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
https://www.cocos.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::unordered_set;
|
||||
|
||||
namespace pmr {
|
||||
template <
|
||||
class Key,
|
||||
class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>>
|
||||
using unordered_set = std::unordered_set<Key, Hash, KeyEqual, boost::container::pmr::polymorphic_allocator<Key>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
37
cocos/base/std/container/vector.h
Normal file
37
cocos/base/std/container/vector.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2022-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "boost/container/pmr/polymorphic_allocator.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
using std::vector;
|
||||
|
||||
namespace pmr {
|
||||
template <class T>
|
||||
using vector = std::vector<T, boost::container::pmr::polymorphic_allocator<T>>;
|
||||
}
|
||||
} // namespace ccstd
|
||||
336
cocos/base/std/hash/detail/float_functions.hpp
Normal file
336
cocos/base/std/hash/detail/float_functions.hpp
Normal file
@@ -0,0 +1,336 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP)
|
||||
#define CCSTD_FUNCTIONAL_HASH_DETAIL_FLOAT_FUNCTIONS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
|
||||
// Set BOOST_HASH_CONFORMANT_FLOATS to 1 for libraries known to have
|
||||
// sufficiently good floating point support to not require any
|
||||
// workarounds.
|
||||
//
|
||||
// When set to 0, the library tries to automatically
|
||||
// use the best available implementation. This normally works well, but
|
||||
// breaks when ambiguities are created by odd namespacing of the functions.
|
||||
//
|
||||
// Note that if this is set to 0, the library should still take full
|
||||
// advantage of the platform's floating point support.
|
||||
|
||||
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif defined(__LIBCOMO__)
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
||||
// Rogue Wave library:
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif defined(_LIBCPP_VERSION)
|
||||
// libc++
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 1
|
||||
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
// GNU libstdc++ 3
|
||||
# if defined(__GNUC__) && __GNUC__ >= 4
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 1
|
||||
# else
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
# endif
|
||||
#elif defined(__STL_CONFIG_H)
|
||||
// generic SGI STL
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif defined(__MSL_CPP__)
|
||||
// MSL standard lib:
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif defined(__IBMCPP__)
|
||||
// VACPP std lib (probably conformant for much earlier version).
|
||||
# if __IBMCPP__ >= 1210
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 1
|
||||
# else
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
# endif
|
||||
#elif defined(MSIPL_COMPILE_H)
|
||||
// Modena C++ standard library
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
|
||||
// Dinkumware Library (this has to appear after any possible replacement libraries):
|
||||
# if _CPPLIB_VER >= 405
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 1
|
||||
# else
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_HASH_CONFORMANT_FLOATS 0
|
||||
#endif
|
||||
|
||||
#if BOOST_HASH_CONFORMANT_FLOATS
|
||||
|
||||
// The standard library is known to be compliant, so don't use the
|
||||
// configuration mechanism.
|
||||
|
||||
namespace ccstd {
|
||||
namespace hash_detail {
|
||||
template <typename Float>
|
||||
struct call_ldexp {
|
||||
typedef Float float_type;
|
||||
inline Float operator()(Float x, int y) const {
|
||||
return std::ldexp(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Float>
|
||||
struct call_frexp {
|
||||
typedef Float float_type;
|
||||
inline Float operator()(Float x, int* y) const {
|
||||
return std::frexp(x, y);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Float>
|
||||
struct select_hash_type
|
||||
{
|
||||
typedef Float type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#else // BOOST_HASH_CONFORMANT_FLOATS == 0
|
||||
|
||||
// The C++ standard requires that the C float functions are overloarded
|
||||
// for float, double and long double in the std namespace, but some of the older
|
||||
// library implementations don't support this. On some that don't, the C99
|
||||
// float functions (frexpf, frexpl, etc.) are available.
|
||||
//
|
||||
// The following tries to automatically detect which are available.
|
||||
|
||||
namespace ccstd {
|
||||
namespace hash_detail {
|
||||
|
||||
// Returned by dummy versions of the float functions.
|
||||
|
||||
struct not_found {
|
||||
// Implicitly convertible to float and long double in order to avoid
|
||||
// a compile error when the dummy float functions are used.
|
||||
|
||||
inline operator float() const { return 0; }
|
||||
inline operator long double() const { return 0; }
|
||||
};
|
||||
|
||||
// A type for detecting the return type of functions.
|
||||
|
||||
template <typename T> struct is;
|
||||
template <> struct is<float> { char x[10]; };
|
||||
template <> struct is<double> { char x[20]; };
|
||||
template <> struct is<long double> { char x[30]; };
|
||||
template <> struct is<boost::hash_detail::not_found> { char x[40]; };
|
||||
|
||||
// Used to convert the return type of a function to a type for sizeof.
|
||||
|
||||
template <typename T> is<T> float_type(T);
|
||||
|
||||
// call_ldexp
|
||||
//
|
||||
// This will get specialized for float and long double
|
||||
|
||||
template <typename Float> struct call_ldexp
|
||||
{
|
||||
typedef double float_type;
|
||||
|
||||
inline double operator()(double a, int b) const
|
||||
{
|
||||
using namespace std;
|
||||
return ldexp(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
// call_frexp
|
||||
//
|
||||
// This will get specialized for float and long double
|
||||
|
||||
template <typename Float> struct call_frexp
|
||||
{
|
||||
typedef double float_type;
|
||||
|
||||
inline double operator()(double a, int* b) const
|
||||
{
|
||||
using namespace std;
|
||||
return frexp(a, b);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// A namespace for dummy functions to detect when the actual function we want
|
||||
// isn't available. ldexpl, ldexpf etc. might be added tby the macros below.
|
||||
//
|
||||
// AFAICT these have to be outside of the boost namespace, as if they're in
|
||||
// the boost namespace they'll always be preferable to any other function
|
||||
// (since the arguments are built in types, ADL can't be used).
|
||||
|
||||
namespace ccstd_hash_detect_float_functions {
|
||||
template <class Float> boost::hash_detail::not_found ldexp(Float, int);
|
||||
template <class Float> boost::hash_detail::not_found frexp(Float, int*);
|
||||
}
|
||||
|
||||
// Macros for generating specializations of call_ldexp and call_frexp.
|
||||
//
|
||||
// check_cpp and check_c99 check if the C++ or C99 functions are available.
|
||||
//
|
||||
// Then the call_* functions select an appropriate implementation.
|
||||
//
|
||||
// I used c99_func in a few places just to get a unique name.
|
||||
//
|
||||
// Important: when using 'using namespace' at namespace level, include as
|
||||
// little as possible in that namespace, as Visual C++ has an odd bug which
|
||||
// can cause the namespace to be imported at the global level. This seems to
|
||||
// happen mainly when there's a template in the same namesapce.
|
||||
|
||||
#define BOOST_HASH_CALL_FLOAT_FUNC(cpp_func, c99_func, type1, type2) \
|
||||
namespace ccstd_hash_detect_float_functions { \
|
||||
template <class Float> \
|
||||
boost::hash_detail::not_found c99_func(Float, type2); \
|
||||
} \
|
||||
\
|
||||
namespace ccstd { \
|
||||
namespace hash_detail { \
|
||||
namespace c99_func##_detect { \
|
||||
using namespace std; \
|
||||
using namespace ccstd_hash_detect_float_functions; \
|
||||
\
|
||||
struct check { \
|
||||
static type1 x; \
|
||||
static type2 y; \
|
||||
BOOST_STATIC_CONSTANT(bool, cpp = \
|
||||
sizeof(float_type(cpp_func(x,y))) \
|
||||
== sizeof(is<type1>)); \
|
||||
BOOST_STATIC_CONSTANT(bool, c99 = \
|
||||
sizeof(float_type(c99_func(x,y))) \
|
||||
== sizeof(is<type1>)); \
|
||||
}; \
|
||||
} \
|
||||
\
|
||||
template <bool x> \
|
||||
struct call_c99_##c99_func : \
|
||||
boost::hash_detail::call_##cpp_func<double> {}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_c99_##c99_func<true> { \
|
||||
typedef type1 float_type; \
|
||||
\
|
||||
template <typename T> \
|
||||
inline type1 operator()(type1 a, T b) const \
|
||||
{ \
|
||||
using namespace std; \
|
||||
return c99_func(a, b); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <bool x> \
|
||||
struct call_cpp_##c99_func : \
|
||||
call_c99_##c99_func< \
|
||||
::boost::hash_detail::c99_func##_detect::check::c99 \
|
||||
> {}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_cpp_##c99_func<true> { \
|
||||
typedef type1 float_type; \
|
||||
\
|
||||
template <typename T> \
|
||||
inline type1 operator()(type1 a, T b) const \
|
||||
{ \
|
||||
using namespace std; \
|
||||
return cpp_func(a, b); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <> \
|
||||
struct call_##cpp_func<type1> : \
|
||||
call_cpp_##c99_func< \
|
||||
::boost::hash_detail::c99_func##_detect::check::cpp \
|
||||
> {}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define BOOST_HASH_CALL_FLOAT_MACRO(cpp_func, c99_func, type1, type2) \
|
||||
namespace ccstd { \
|
||||
namespace hash_detail { \
|
||||
\
|
||||
template <> \
|
||||
struct call_##cpp_func<type1> { \
|
||||
typedef type1 float_type; \
|
||||
inline type1 operator()(type1 x, type2 y) const { \
|
||||
return c99_func(x, y); \
|
||||
} \
|
||||
}; \
|
||||
} \
|
||||
}
|
||||
|
||||
#if defined(ldexpf)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpf, float, int)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpf, float, int)
|
||||
#endif
|
||||
|
||||
#if defined(ldexpl)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(ldexp, ldexpl, long double, int)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(ldexp, ldexpl, long double, int)
|
||||
#endif
|
||||
|
||||
#if defined(frexpf)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpf, float, int*)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpf, float, int*)
|
||||
#endif
|
||||
|
||||
#if defined(frexpl)
|
||||
BOOST_HASH_CALL_FLOAT_MACRO(frexp, frexpl, long double, int*)
|
||||
#else
|
||||
BOOST_HASH_CALL_FLOAT_FUNC(frexp, frexpl, long double, int*)
|
||||
#endif
|
||||
|
||||
#undef BOOST_HASH_CALL_FLOAT_MACRO
|
||||
#undef BOOST_HASH_CALL_FLOAT_FUNC
|
||||
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <typename Float1, typename Float2>
|
||||
struct select_hash_type_impl {
|
||||
typedef double type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct select_hash_type_impl<float, float> {
|
||||
typedef float type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct select_hash_type_impl<long double, long double> {
|
||||
typedef long double type;
|
||||
};
|
||||
|
||||
|
||||
// select_hash_type
|
||||
//
|
||||
// If there is support for a particular floating point type, use that
|
||||
// otherwise use double (there's always support for double).
|
||||
|
||||
template <typename Float>
|
||||
struct select_hash_type : select_hash_type_impl<
|
||||
BOOST_DEDUCED_TYPENAME call_ldexp<Float>::float_type,
|
||||
BOOST_DEDUCED_TYPENAME call_frexp<Float>::float_type
|
||||
> {};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_HASH_CONFORMANT_FLOATS
|
||||
|
||||
#endif
|
||||
271
cocos/base/std/hash/detail/hash_float.hpp
Normal file
271
cocos/base/std/hash/detail/hash_float.hpp
Normal file
@@ -0,0 +1,271 @@
|
||||
|
||||
// Copyright 2005-2012 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER)
|
||||
#define CCSTD_FUNCTIONAL_HASH_DETAIL_HASH_FLOAT_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "base/std/hash/detail/float_functions.hpp"
|
||||
#include "base/std/hash/detail/limits.hpp"
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/integer/static_log2.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#if BOOST_MSVC >= 1400
|
||||
#pragma warning(disable:6294) // Ill-defined for-loop: initial condition does
|
||||
// not satisfy test. Loop body not executed
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Can we use fpclassify?
|
||||
|
||||
// STLport
|
||||
#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
#define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
|
||||
// GNU libstdc++ 3
|
||||
#elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
# if (defined(__USE_ISOC99) || defined(_GLIBCXX_USE_C99_MATH)) && \
|
||||
!(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 1
|
||||
# else
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
# endif
|
||||
|
||||
// Everything else
|
||||
#else
|
||||
# define BOOST_HASH_USE_FPCLASSIFY 0
|
||||
#endif
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
inline void hash_float_combine(ccstd::hash_t& seed, ccstd::hash_t value)
|
||||
{
|
||||
seed ^= value + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Binary hash function
|
||||
//
|
||||
// Only used for floats with known iec559 floats, and certain values in
|
||||
// numeric_limits
|
||||
|
||||
inline ccstd::hash_t hash_binary(char* ptr, ccstd::hash_t length)
|
||||
{
|
||||
ccstd::hash_t seed = 0;
|
||||
|
||||
if (length >= sizeof(ccstd::hash_t)) {
|
||||
std::memcpy(&seed, ptr, sizeof(ccstd::hash_t));
|
||||
length -= sizeof(ccstd::hash_t);
|
||||
ptr += sizeof(ccstd::hash_t);
|
||||
|
||||
while(length >= sizeof(ccstd::hash_t)) {
|
||||
ccstd::hash_t buffer = 0;
|
||||
std::memcpy(&buffer, ptr, sizeof(ccstd::hash_t));
|
||||
hash_float_combine(seed, buffer);
|
||||
length -= sizeof(ccstd::hash_t);
|
||||
ptr += sizeof(ccstd::hash_t);
|
||||
}
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
ccstd::hash_t buffer = 0;
|
||||
std::memcpy(&buffer, ptr, length);
|
||||
hash_float_combine(seed, buffer);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <typename Float, unsigned digits, unsigned max_exponent>
|
||||
struct enable_binary_hash
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
std::numeric_limits<Float>::is_iec559 &&
|
||||
std::numeric_limits<Float>::digits == digits &&
|
||||
std::numeric_limits<Float>::radix == 2 &&
|
||||
std::numeric_limits<Float>::max_exponent == max_exponent);
|
||||
};
|
||||
|
||||
template <typename Float>
|
||||
inline ccstd::hash_t float_hash_impl(Float v,
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
|
||||
enable_binary_hash<Float, 24, 128>::value,
|
||||
ccstd::hash_t>::type)
|
||||
{
|
||||
return hash_binary((char*) &v, 4);
|
||||
}
|
||||
|
||||
|
||||
template <typename Float>
|
||||
inline ccstd::hash_t float_hash_impl(Float v,
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
|
||||
enable_binary_hash<Float, 53, 1024>::value,
|
||||
ccstd::hash_t>::type)
|
||||
{
|
||||
return hash_binary((char*) &v, 8);
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
inline ccstd::hash_t float_hash_impl(Float v,
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
|
||||
enable_binary_hash<Float, 64, 16384>::value,
|
||||
ccstd::hash_t>::type)
|
||||
{
|
||||
return hash_binary((char*) &v, 10);
|
||||
}
|
||||
|
||||
template <typename Float>
|
||||
inline ccstd::hash_t float_hash_impl(Float v,
|
||||
BOOST_DEDUCED_TYPENAME boost::enable_if_c<
|
||||
enable_binary_hash<Float, 113, 16384>::value,
|
||||
ccstd::hash_t>::type)
|
||||
{
|
||||
return hash_binary((char*) &v, 16);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Portable hash function
|
||||
//
|
||||
// Used as a fallback when the binary hash function isn't supported.
|
||||
|
||||
template <class T>
|
||||
inline ccstd::hash_t float_hash_impl2(T v)
|
||||
{
|
||||
boost::hash_detail::call_frexp<T> frexp;
|
||||
boost::hash_detail::call_ldexp<T> ldexp;
|
||||
|
||||
int exp = 0;
|
||||
|
||||
v = frexp(v, &exp);
|
||||
|
||||
// A postive value is easier to hash, so combine the
|
||||
// sign with the exponent and use the absolute value.
|
||||
if(v < 0) {
|
||||
v = -v;
|
||||
exp += limits<T>::max_exponent -
|
||||
limits<T>::min_exponent;
|
||||
}
|
||||
|
||||
v = ldexp(v, limits<ccstd::hash_t>::digits);
|
||||
ccstd::hash_t seed = static_cast<ccstd::hash_t>(v);
|
||||
v -= static_cast<T>(seed);
|
||||
|
||||
// ceiling(digits(T) * log2(radix(T))/ digits(size_t)) - 1;
|
||||
ccstd::hash_t const length
|
||||
= (limits<T>::digits *
|
||||
boost::static_log2<limits<T>::radix>::value
|
||||
+ limits<ccstd::hash_t>::digits - 1)
|
||||
/ limits<ccstd::hash_t>::digits;
|
||||
|
||||
for(ccstd::hash_t i = 0; i != length; ++i)
|
||||
{
|
||||
v = ldexp(v, limits<ccstd::hash_t>::digits);
|
||||
ccstd::hash_t part = static_cast<ccstd::hash_t>(v);
|
||||
v -= static_cast<T>(part);
|
||||
hash_float_combine(seed, part);
|
||||
}
|
||||
|
||||
hash_float_combine(seed, static_cast<ccstd::hash_t>(exp));
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_HASH_DETAIL_TEST_WITHOUT_GENERIC)
|
||||
template <class T>
|
||||
inline ccstd::hash_t float_hash_impl(T v, ...)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME select_hash_type<T>::type type;
|
||||
return float_hash_impl2(static_cast<type>(v));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#include <boost/config/no_tr1/cmath.hpp>
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline ccstd::hash_t float_hash_value(T v)
|
||||
{
|
||||
#if defined(fpclassify)
|
||||
switch (fpclassify(v))
|
||||
#elif BOOST_HASH_CONFORMANT_FLOATS
|
||||
switch (std::fpclassify(v))
|
||||
#else
|
||||
using namespace std;
|
||||
switch (fpclassify(v))
|
||||
#endif
|
||||
{
|
||||
case FP_ZERO:
|
||||
return 0;
|
||||
case FP_INFINITE:
|
||||
return (ccstd::hash_t)(v > 0 ? -1 : -2);
|
||||
case FP_NAN:
|
||||
return (ccstd::hash_t)(-3);
|
||||
case FP_NORMAL:
|
||||
case FP_SUBNORMAL:
|
||||
return float_hash_impl(v, 0);
|
||||
default:
|
||||
BOOST_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // !BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline bool is_zero(T v)
|
||||
{
|
||||
#if !defined(__GNUC__) && !defined(__clang__)
|
||||
return v == 0;
|
||||
#else
|
||||
// GCC's '-Wfloat-equal' will complain about comparing
|
||||
// v to 0, but because it disables warnings for system
|
||||
// headers it won't complain if you use std::equal_to to
|
||||
// compare with 0. Resulting in this silliness:
|
||||
return std::equal_to<T>()(v, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ccstd::hash_t float_hash_value(T v)
|
||||
{
|
||||
return boost::hash_detail::is_zero(v) ? 0 : float_hash_impl(v, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#undef BOOST_HASH_USE_FPCLASSIFY
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
62
cocos/base/std/hash/detail/limits.hpp
Normal file
62
cocos/base/std/hash/detail/limits.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// On some platforms std::limits gives incorrect values for long double.
|
||||
// This tries to work around them.
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER)
|
||||
#define CCSTD_FUNCTIONAL_HASH_DETAIL_LIMITS_HEADER
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
// On OpenBSD, numeric_limits is not reliable for long doubles, but
|
||||
// the macros defined in <float.h> are and support long double when STLport
|
||||
// doesn't.
|
||||
|
||||
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
struct limits : std::numeric_limits<T> {};
|
||||
|
||||
#if defined(__OpenBSD__) || defined(_STLP_NO_LONG_DOUBLE)
|
||||
template <>
|
||||
struct limits<long double>
|
||||
: std::numeric_limits<long double>
|
||||
{
|
||||
static long double epsilon() {
|
||||
return LDBL_EPSILON;
|
||||
}
|
||||
|
||||
static long double (max)() {
|
||||
return LDBL_MAX;
|
||||
}
|
||||
|
||||
static long double (min)() {
|
||||
return LDBL_MIN;
|
||||
}
|
||||
|
||||
BOOST_STATIC_CONSTANT(int, digits = LDBL_MANT_DIG);
|
||||
BOOST_STATIC_CONSTANT(int, max_exponent = LDBL_MAX_EXP);
|
||||
BOOST_STATIC_CONSTANT(int, min_exponent = LDBL_MIN_EXP);
|
||||
#if defined(_STLP_NO_LONG_DOUBLE)
|
||||
BOOST_STATIC_CONSTANT(int, radix = FLT_RADIX);
|
||||
#endif
|
||||
};
|
||||
#endif // __OpenBSD__
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
361
cocos/base/std/hash/extensions.hpp
Normal file
361
cocos/base/std/hash/extensions.hpp
Normal file
@@ -0,0 +1,361 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
// This implements the extensions to the standard.
|
||||
// It's undocumented, so you shouldn't use it....
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_EXTENSIONS_HPP)
|
||||
#define CCSTD_FUNCTIONAL_HASH_EXTENSIONS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "base/std/hash/hash.h"
|
||||
#include <boost/detail/container_fwd.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
|
||||
# include <array>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
# include <tuple>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#endif
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
template <class A, class B>
|
||||
hash_t hash_value(std::pair<A, B> const&);
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::vector<T, A> const&);
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::list<T, A> const& v);
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::deque<T, A> const& v);
|
||||
template <class K, class C, class A>
|
||||
hash_t hash_value(std::set<K, C, A> const& v);
|
||||
template <class K, class C, class A>
|
||||
hash_t hash_value(std::multiset<K, C, A> const& v);
|
||||
template <class K, class T, class C, class A>
|
||||
hash_t hash_value(std::map<K, T, C, A> const& v);
|
||||
template <class K, class T, class C, class A>
|
||||
hash_t hash_value(std::multimap<K, T, C, A> const& v);
|
||||
|
||||
template <class T>
|
||||
hash_t hash_value(std::complex<T> const&);
|
||||
|
||||
template <class A, class B>
|
||||
hash_t hash_value(std::pair<A, B> const& v)
|
||||
{
|
||||
hash_t seed = 0;
|
||||
ccstd::hash_combine(seed, v.first);
|
||||
ccstd::hash_combine(seed, v.second);
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::vector<T, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::list<T, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T, class A>
|
||||
hash_t hash_value(std::deque<T, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class C, class A>
|
||||
hash_t hash_value(std::set<K, C, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class C, class A>
|
||||
hash_t hash_value(std::multiset<K, C, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class C, class A>
|
||||
hash_t hash_value(std::map<K, T, C, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class C, class A>
|
||||
hash_t hash_value(std::multimap<K, T, C, A> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hash_t hash_value(std::complex<T> const& v)
|
||||
{
|
||||
ccstd::hash<T> hasher;
|
||||
hash_t seed = hasher(v.imag());
|
||||
seed ^= hasher(v.real()) + (seed<<6) + (seed>>2);
|
||||
return seed;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_ARRAY)
|
||||
template <class T, std::size_t N>
|
||||
hash_t hash_value(std::array<T, N> const& v)
|
||||
{
|
||||
return ccstd::hash_range(v.begin(), v.end());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
namespace hash_detail {
|
||||
template <std::size_t I, typename T>
|
||||
inline typename boost::enable_if_c<(I == std::tuple_size<T>::value),
|
||||
void>::type
|
||||
hash_combine_tuple(hash_t&, T const&)
|
||||
{
|
||||
}
|
||||
|
||||
template <std::size_t I, typename T>
|
||||
inline typename boost::enable_if_c<(I < std::tuple_size<T>::value),
|
||||
void>::type
|
||||
hash_combine_tuple(hash_t& seed, T const& v)
|
||||
{
|
||||
ccstd::hash_combine(seed, std::get<I>(v));
|
||||
ccstd::hash_detail::hash_combine_tuple<I + 1>(seed, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline hash_t hash_tuple(T const& v)
|
||||
{
|
||||
hash_t seed = 0;
|
||||
ccstd::hash_detail::hash_combine_tuple<0>(seed, v);
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <typename... T>
|
||||
inline hash_t hash_value(std::tuple<T...> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
#else
|
||||
|
||||
inline hash_t hash_value(std::tuple<> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0>
|
||||
inline hash_t hash_value(std::tuple<A0> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1>
|
||||
inline hash_t hash_value(std::tuple<A0, A1> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
template<typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9>
|
||||
inline hash_t hash_value(std::tuple<A0, A1, A2, A3, A4, A5, A6, A7, A8, A9> const& v)
|
||||
{
|
||||
return ccstd::hash_detail::hash_tuple(v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_SMART_PTR)
|
||||
template <typename T>
|
||||
inline hash_t hash_value(std::shared_ptr<T> const& x) {
|
||||
return ccstd::hash_value(x.get());
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
inline hash_t hash_value(std::unique_ptr<T, Deleter> const& x) {
|
||||
return ccstd::hash_value(x.get());
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// call_hash_impl
|
||||
//
|
||||
|
||||
// On compilers without function template ordering, this deals with arrays.
|
||||
|
||||
#if defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsArray>
|
||||
struct call_hash_impl
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
{
|
||||
static hash_t call(T const& v)
|
||||
{
|
||||
using namespace ccstd;
|
||||
return hash_value(v);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <>
|
||||
struct call_hash_impl<true>
|
||||
{
|
||||
template <class Array>
|
||||
struct inner
|
||||
{
|
||||
static hash_t call(Array const& v)
|
||||
{
|
||||
const int size = sizeof(v) / sizeof(*v);
|
||||
return ccstd::hash_range(v, v + size);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct call_hash
|
||||
: public call_hash_impl<ccstd::is_array<T>::value>
|
||||
::BOOST_NESTED_TEMPLATE inner<T>
|
||||
{
|
||||
};
|
||||
}
|
||||
#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING
|
||||
|
||||
//
|
||||
// ccstd::hash
|
||||
//
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
template <class T> struct hash
|
||||
: ccstd::hash_detail::hash_base<T>
|
||||
{
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
hash_t operator()(T const& val) const
|
||||
{
|
||||
return hash_value(val);
|
||||
}
|
||||
#else
|
||||
hash_t operator()(T const& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#if BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T, unsigned int n> struct hash<T[n]>
|
||||
: ccstd::hash_detail::hash_base<T[n]>
|
||||
{
|
||||
hash_t operator()(const T* val) const
|
||||
{
|
||||
return ccstd::hash_range(val, val+n);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
|
||||
// On compilers without partial specialization, ccstd::hash<T>
|
||||
// has already been declared to deal with pointers, so just
|
||||
// need to supply the non-pointer version of hash_impl.
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsPointer>
|
||||
struct hash_impl;
|
||||
|
||||
template <>
|
||||
struct hash_impl<false>
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: ccstd::hash_detail::hash_base<T>
|
||||
{
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
hash_t operator()(T const& val) const
|
||||
{
|
||||
return hash_value(val);
|
||||
}
|
||||
#else
|
||||
hash_t operator()(T const& val) const
|
||||
{
|
||||
return hash_detail::call_hash<T>::call(val);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};
|
||||
}
|
||||
#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
}
|
||||
|
||||
#endif
|
||||
783
cocos/base/std/hash/hash.h
Normal file
783
cocos/base/std/hash/hash.h
Normal file
@@ -0,0 +1,783 @@
|
||||
|
||||
// Copyright 2005-2014 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
//
|
||||
// This also contains public domain code from MurmurHash. From the
|
||||
// MurmurHash header:
|
||||
|
||||
// MurmurHash3 was written by Austin Appleby, and is placed in the public
|
||||
// domain. The author hereby disclaims copyright to this source code.
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_HASH_HPP)
|
||||
#define CCSTD_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
#include "boost/container_hash/hash.hpp"
|
||||
|
||||
#include "base/std/hash/hash_fwd.hpp"
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include "base/std/hash/detail/hash_float.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/type_traits/is_enum.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <climits>
|
||||
|
||||
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
#include <typeindex>
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
|
||||
#include <system_error>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
|
||||
#if BOOST_MSVC >= 1400
|
||||
#pragma warning(disable:6295) // Ill-defined for-loop : 'unsigned int' values
|
||||
// are always of range '0' to '4294967295'.
|
||||
// Loop executes infinitely.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__GNUC__, < 3) \
|
||||
&& !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)
|
||||
#define CCSTD_HASH_CHAR_TRAITS string_char_traits
|
||||
#else
|
||||
#define CCSTD_HASH_CHAR_TRAITS char_traits
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define CCSTD_FUNCTIONAL_HASH_ROTL32(x, r) _rotl(x,r)
|
||||
#else
|
||||
# define CCSTD_FUNCTIONAL_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r))
|
||||
#endif
|
||||
|
||||
// Detect whether standard library has C++17 headers
|
||||
|
||||
#if !defined(CCSTD_HASH_CXX17)
|
||||
# if defined(BOOST_MSVC)
|
||||
# if defined(_HAS_CXX17) && _HAS_CXX17
|
||||
# define CCSTD_HASH_CXX17 1
|
||||
# endif
|
||||
# elif defined(__cplusplus) && __cplusplus >= 201703
|
||||
# define CCSTD_HASH_CXX17 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(CCSTD_HASH_CXX17)
|
||||
# define CCSTD_HASH_CXX17 0
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_CXX17 && defined(__has_include)
|
||||
# if !defined(CCSTD_HASH_HAS_STRING_VIEW) && __has_include(<string_view>)
|
||||
# define CCSTD_HASH_HAS_STRING_VIEW 1
|
||||
# endif
|
||||
# if !defined(CCSTD_HASH_HAS_OPTIONAL) && __has_include(<optional>)
|
||||
# define CCSTD_HASH_HAS_OPTIONAL 1
|
||||
# endif
|
||||
# if !defined(CCSTD_HASH_HAS_VARIANT) && __has_include(<variant>)
|
||||
# define CCSTD_HASH_HAS_VARIANT 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(CCSTD_HASH_HAS_STRING_VIEW)
|
||||
# define CCSTD_HASH_HAS_STRING_VIEW 0
|
||||
#endif
|
||||
|
||||
#if !defined(CCSTD_HASH_HAS_OPTIONAL)
|
||||
# define CCSTD_HASH_HAS_OPTIONAL 0
|
||||
#endif
|
||||
|
||||
#if !defined(CCSTD_HASH_HAS_VARIANT)
|
||||
# define CCSTD_HASH_HAS_VARIANT 0
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_STRING_VIEW
|
||||
# include <string_view>
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_OPTIONAL
|
||||
# include <optional>
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_VARIANT
|
||||
# include <variant>
|
||||
#endif
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
namespace hash_detail
|
||||
{
|
||||
#if defined(BOOST_NO_CXX98_FUNCTION_BASE)
|
||||
template <typename T>
|
||||
struct hash_base
|
||||
{
|
||||
typedef T argument_type;
|
||||
typedef hash_t result_type;
|
||||
};
|
||||
#else
|
||||
template <typename T>
|
||||
struct hash_base : std::unary_function<T, hash_t> {};
|
||||
#endif
|
||||
|
||||
struct enable_hash_value { typedef hash_t type; };
|
||||
|
||||
template <typename T> struct basic_numbers {};
|
||||
template <typename T> struct long_numbers;
|
||||
template <typename T> struct ulong_numbers;
|
||||
template <typename T> struct float_numbers {};
|
||||
|
||||
template <> struct basic_numbers<bool> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<char> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<unsigned char> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<signed char> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<short> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<unsigned short> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<int> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<unsigned int> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<long> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct basic_numbers<unsigned long> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
template <> struct basic_numbers<wchar_t> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
template <> struct basic_numbers<char16_t> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
template <> struct basic_numbers<char32_t> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
#endif
|
||||
|
||||
// long_numbers is defined like this to allow for separate
|
||||
// specialization for long_long and int128_type, in case
|
||||
// they conflict.
|
||||
template <typename T> struct long_numbers2 {};
|
||||
template <typename T> struct ulong_numbers2 {};
|
||||
template <typename T> struct long_numbers : long_numbers2<T> {};
|
||||
template <typename T> struct ulong_numbers : ulong_numbers2<T> {};
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
template <> struct long_numbers<boost::long_long_type> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct ulong_numbers<boost::ulong_long_type> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
template <> struct long_numbers2<boost::int128_type> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct ulong_numbers2<boost::uint128_type> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
#endif
|
||||
|
||||
template <> struct float_numbers<float> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct float_numbers<double> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
template <> struct float_numbers<long double> :
|
||||
ccstd::hash_detail::enable_hash_value {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::basic_numbers<T>::type hash_value(T);
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::long_numbers<T>::type hash_value(T);
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::ulong_numbers<T>::type hash_value(T);
|
||||
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_enum<T>, hash_t>::type
|
||||
hash_value(T);
|
||||
|
||||
#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T> hash_t hash_value(T* const&);
|
||||
#else
|
||||
template <class T> hash_t hash_value(T*);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
template< class T, unsigned N >
|
||||
hash_t hash_value(const T (&x)[N]);
|
||||
|
||||
template< class T, unsigned N >
|
||||
hash_t hash_value(T (&x)[N]);
|
||||
#endif
|
||||
|
||||
template <class Ch, class A>
|
||||
hash_t hash_value(
|
||||
std::basic_string<Ch, std::CCSTD_HASH_CHAR_TRAITS<Ch>, A> const&);
|
||||
|
||||
#if CCSTD_HASH_HAS_STRING_VIEW
|
||||
template <class Ch>
|
||||
hash_t hash_value(
|
||||
std::basic_string_view<Ch, std::CCSTD_HASH_CHAR_TRAITS<Ch> > const&);
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::float_numbers<T>::type hash_value(T);
|
||||
|
||||
#if CCSTD_HASH_HAS_OPTIONAL
|
||||
template <typename T>
|
||||
hash_t hash_value(std::optional<T> const&);
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_VARIANT
|
||||
hash_t hash_value(std::monostate);
|
||||
template <typename... Types>
|
||||
hash_t hash_value(std::variant<Types...> const&);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
hash_t hash_value(std::type_index);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
|
||||
hash_t hash_value(std::error_code const&);
|
||||
hash_t hash_value(std::error_condition const&);
|
||||
#endif
|
||||
|
||||
// Implementation
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <class T>
|
||||
inline hash_t hash_value_signed(T val)
|
||||
{
|
||||
const unsigned int size_t_bits = std::numeric_limits<hash_t>::digits;
|
||||
// ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
|
||||
const int length = (std::numeric_limits<T>::digits - 1)
|
||||
/ static_cast<int>(size_t_bits);
|
||||
|
||||
hash_t seed = 0;
|
||||
T positive = val < 0 ? -1 - val : val;
|
||||
|
||||
// Hopefully, this loop can be unrolled.
|
||||
for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
|
||||
{
|
||||
seed ^= (hash_t) (positive >> i) + (seed<<6) + (seed>>2);
|
||||
}
|
||||
seed ^= (hash_t) val + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline hash_t hash_value_unsigned(T val)
|
||||
{
|
||||
const unsigned int size_t_bits = std::numeric_limits<hash_t>::digits;
|
||||
// ceiling(std::numeric_limits<T>::digits / size_t_bits) - 1
|
||||
const int length = (std::numeric_limits<T>::digits - 1)
|
||||
/ static_cast<int>(size_t_bits);
|
||||
|
||||
hash_t seed = 0;
|
||||
|
||||
// Hopefully, this loop can be unrolled.
|
||||
for(unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
|
||||
{
|
||||
seed ^= (hash_t) (val >> i) + (seed<<6) + (seed>>2);
|
||||
}
|
||||
seed ^= (hash_t) val + (seed<<6) + (seed>>2);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template<hash_t Bits> struct hash_combine_impl
|
||||
{
|
||||
template <typename SizeT>
|
||||
inline static SizeT fn(SizeT seed, SizeT value)
|
||||
{
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_combine_impl<32>
|
||||
{
|
||||
inline static std::uint32_t fn(std::uint32_t h1, std::uint32_t k1)
|
||||
{
|
||||
const std::uint32_t c1 = 0xcc9e2d51;
|
||||
const std::uint32_t c2 = 0x1b873593;
|
||||
|
||||
k1 *= c1;
|
||||
k1 = CCSTD_FUNCTIONAL_HASH_ROTL32(k1,15);
|
||||
k1 *= c2;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = CCSTD_FUNCTIONAL_HASH_ROTL32(h1,13);
|
||||
h1 = h1*5+0xe6546b64;
|
||||
|
||||
return h1;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct hash_combine_impl<64>
|
||||
{
|
||||
inline static std::uint64_t fn(std::uint64_t h, std::uint64_t k)
|
||||
{
|
||||
const std::uint64_t m = (std::uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
|
||||
const int r = 47;
|
||||
|
||||
k *= m;
|
||||
k ^= k >> r;
|
||||
k *= m;
|
||||
|
||||
h ^= k;
|
||||
h *= m;
|
||||
|
||||
// Completely arbitrary number, to prevent 0's
|
||||
// from hashing to 0.
|
||||
h += 0xe6546b64;
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::basic_numbers<T>::type hash_value(T v)
|
||||
{
|
||||
return static_cast<hash_t>(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::long_numbers<T>::type hash_value(T v)
|
||||
{
|
||||
return hash_detail::hash_value_signed(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::ulong_numbers<T>::type hash_value(T v)
|
||||
{
|
||||
return hash_detail::hash_value_unsigned(v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename boost::enable_if<boost::is_enum<T>, hash_t>::type
|
||||
hash_value(T v)
|
||||
{
|
||||
return static_cast<hash_t>(v);
|
||||
}
|
||||
|
||||
// Implementation by Alberto Barbati and Dave Harris.
|
||||
#if !BOOST_WORKAROUND(__DMC__, <= 0x848)
|
||||
template <class T> hash_t hash_value(T* const& v)
|
||||
#else
|
||||
template <class T> hash_t hash_value(T* v)
|
||||
#endif
|
||||
{
|
||||
#if defined(__VMS) && __INITIAL_POINTER_SIZE == 64
|
||||
// for some reason ptrdiff_t on OpenVMS compiler with
|
||||
// 64 bit is not 64 bit !!!
|
||||
hash_t x = static_cast<hash_t>(
|
||||
reinterpret_cast<long long int>(v));
|
||||
#else
|
||||
hash_t x = static_cast<hash_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(v));
|
||||
#endif
|
||||
return x + (x >> 3);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#if BOOST_MSVC <= 1400
|
||||
#pragma warning(disable:4267) // 'argument' : conversion from 'size_t' to
|
||||
// 'unsigned int', possible loss of data
|
||||
// A misguided attempt to detect 64-bit
|
||||
// incompatability.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(hash_t& seed, T const& v)
|
||||
{
|
||||
ccstd::hash<T> hasher;
|
||||
seed = ccstd::hash_detail::hash_combine_impl<sizeof(hash_t) * CHAR_BIT>::fn(seed, hasher(v));
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <class It>
|
||||
inline hash_t hash_range(It first, It last)
|
||||
{
|
||||
hash_t seed = 0;
|
||||
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
hash_combine<typename std::iterator_traits<It>::value_type>(seed, *first);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class It>
|
||||
inline void hash_range(hash_t& seed, It first, It last)
|
||||
{
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
hash_combine<typename std::iterator_traits<It>::value_type>(seed, *first);
|
||||
}
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551))
|
||||
template <class T>
|
||||
inline hash_t hash_range(T* first, T* last)
|
||||
{
|
||||
hash_t seed = 0;
|
||||
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
ccstd::hash<T> hasher;
|
||||
seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_range(hash_t& seed, T* first, T* last)
|
||||
{
|
||||
for(; first != last; ++first)
|
||||
{
|
||||
ccstd::hash<T> hasher;
|
||||
seed ^= hasher(*first) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING)
|
||||
template< class T, unsigned N >
|
||||
inline hash_t hash_value(const T (&x)[N])
|
||||
{
|
||||
return hash_range(x, x + N);
|
||||
}
|
||||
|
||||
template< class T, unsigned N >
|
||||
inline hash_t hash_value(T (&x)[N])
|
||||
{
|
||||
return hash_range(x, x + N);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Ch, class A>
|
||||
inline hash_t hash_value(
|
||||
std::basic_string<Ch, std::CCSTD_HASH_CHAR_TRAITS<Ch>, A> const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
|
||||
#if CCSTD_HASH_HAS_STRING_VIEW
|
||||
template <class Ch>
|
||||
inline hash_t hash_value(
|
||||
std::basic_string_view<Ch, std::CCSTD_HASH_CHAR_TRAITS<Ch> > const& v)
|
||||
{
|
||||
return hash_range(v.begin(), v.end());
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
typename ccstd::hash_detail::float_numbers<T>::type hash_value(T v)
|
||||
{
|
||||
return ccstd::hash_detail::float_hash_value(v);
|
||||
}
|
||||
|
||||
#if CCSTD_HASH_HAS_OPTIONAL
|
||||
template <typename T>
|
||||
inline hash_t hash_value(std::optional<T> const& v) {
|
||||
if (!v) {
|
||||
// Arbitray value for empty optional.
|
||||
return 0x12345678;
|
||||
} else {
|
||||
ccstd::hash<T> hf;
|
||||
return hf(*v);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_VARIANT
|
||||
inline hash_t hash_value(std::monostate) {
|
||||
return 0x87654321;
|
||||
}
|
||||
|
||||
template <typename... Types>
|
||||
inline hash_t hash_value(std::variant<Types...> const& v) {
|
||||
hash_t seed = 0;
|
||||
hash_combine(seed, v.index());
|
||||
std::visit([&seed](auto&& x) { hash_combine(seed, x); }, v);
|
||||
return seed;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
inline hash_t hash_value(std::type_index v)
|
||||
{
|
||||
size_t hash = v.hash_code();
|
||||
|
||||
#ifndef INTPTR_MAX
|
||||
#error "no INTPTR_MAX"
|
||||
#endif
|
||||
|
||||
#ifndef INT64_MAX
|
||||
#error "no INT64_MAX"
|
||||
#endif
|
||||
|
||||
#if INTPTR_MAX == INT64_MAX
|
||||
hash = (hash >> 32) ^ (hash & 0xFFFFFFFF);
|
||||
#endif
|
||||
return static_cast<hash_t>(hash);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR)
|
||||
inline hash_t hash_value(std::error_code const& v) {
|
||||
hash_t seed = 0;
|
||||
hash_combine(seed, v.value());
|
||||
hash_combine(seed, &v.category());
|
||||
return seed;
|
||||
}
|
||||
|
||||
inline hash_t hash_value(std::error_condition const& v) {
|
||||
hash_t seed = 0;
|
||||
hash_combine(seed, v.value());
|
||||
hash_combine(seed, &v.category());
|
||||
return seed;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// ccstd::hash
|
||||
//
|
||||
|
||||
// Define the specializations required by the standard. The general purpose
|
||||
// ccstd::hash is defined later in extensions.hpp if
|
||||
// CCSTD_HASH_NO_EXTENSIONS is not defined.
|
||||
|
||||
// CCSTD_HASH_SPECIALIZE - define a specialization for a type which is
|
||||
// passed by copy.
|
||||
//
|
||||
// CCSTD_HASH_SPECIALIZE_REF - define a specialization for a type which is
|
||||
// passed by const reference.
|
||||
//
|
||||
// These are undefined later.
|
||||
|
||||
#define CCSTD_HASH_SPECIALIZE(type) \
|
||||
template <> struct hash<type> \
|
||||
: public ccstd::hash_detail::hash_base<type> \
|
||||
{ \
|
||||
hash_t operator()(type v) const \
|
||||
{ \
|
||||
return ccstd::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define CCSTD_HASH_SPECIALIZE_REF(type) \
|
||||
template <> struct hash<type> \
|
||||
: public ccstd::hash_detail::hash_base<type> \
|
||||
{ \
|
||||
hash_t operator()(type const& v) const \
|
||||
{ \
|
||||
return ccstd::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define CCSTD_HASH_SPECIALIZE_TEMPLATE_REF(type) \
|
||||
struct hash<type> \
|
||||
: public ccstd::hash_detail::hash_base<type> \
|
||||
{ \
|
||||
hash_t operator()(type const& v) const \
|
||||
{ \
|
||||
return ccstd::hash_value(v); \
|
||||
} \
|
||||
};
|
||||
|
||||
CCSTD_HASH_SPECIALIZE(bool)
|
||||
CCSTD_HASH_SPECIALIZE(char)
|
||||
CCSTD_HASH_SPECIALIZE(signed char)
|
||||
CCSTD_HASH_SPECIALIZE(unsigned char)
|
||||
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
CCSTD_HASH_SPECIALIZE(wchar_t)
|
||||
#endif
|
||||
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
CCSTD_HASH_SPECIALIZE(char16_t)
|
||||
#endif
|
||||
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
CCSTD_HASH_SPECIALIZE(char32_t)
|
||||
#endif
|
||||
CCSTD_HASH_SPECIALIZE(short)
|
||||
CCSTD_HASH_SPECIALIZE(unsigned short)
|
||||
CCSTD_HASH_SPECIALIZE(int)
|
||||
CCSTD_HASH_SPECIALIZE(unsigned int)
|
||||
CCSTD_HASH_SPECIALIZE(long)
|
||||
CCSTD_HASH_SPECIALIZE(unsigned long)
|
||||
|
||||
CCSTD_HASH_SPECIALIZE(float)
|
||||
CCSTD_HASH_SPECIALIZE(double)
|
||||
CCSTD_HASH_SPECIALIZE(long double)
|
||||
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::string)
|
||||
#if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::wstring)
|
||||
#endif
|
||||
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::basic_string<char16_t>)
|
||||
#endif
|
||||
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::basic_string<char32_t>)
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_STRING_VIEW
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::string_view)
|
||||
# if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_INTRINSIC_WCHAR_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::wstring_view)
|
||||
# endif
|
||||
# if !defined(BOOST_NO_CXX11_CHAR16_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::basic_string_view<char16_t>)
|
||||
# endif
|
||||
# if !defined(BOOST_NO_CXX11_CHAR32_T)
|
||||
CCSTD_HASH_SPECIALIZE_REF(std::basic_string_view<char32_t>)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_LONG_LONG)
|
||||
CCSTD_HASH_SPECIALIZE(boost::long_long_type)
|
||||
CCSTD_HASH_SPECIALIZE(boost::ulong_long_type)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_INT128)
|
||||
CCSTD_HASH_SPECIALIZE(boost::int128_type)
|
||||
CCSTD_HASH_SPECIALIZE(boost::uint128_type)
|
||||
#endif
|
||||
|
||||
#if CCSTD_HASH_HAS_OPTIONAL
|
||||
template <typename T>
|
||||
CCSTD_HASH_SPECIALIZE_TEMPLATE_REF(std::optional<T>)
|
||||
#endif
|
||||
|
||||
#if !defined(CCSTD_HASH_HAS_VARIANT)
|
||||
template <typename... T>
|
||||
CCSTD_HASH_SPECIALIZE_TEMPLATE_REF(std::variant<T...>)
|
||||
CCSTD_HASH_SPECIALIZE(std::monostate)
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TYPEINDEX)
|
||||
CCSTD_HASH_SPECIALIZE(std::type_index)
|
||||
#endif
|
||||
|
||||
#undef CCSTD_HASH_SPECIALIZE
|
||||
#undef CCSTD_HASH_SPECIALIZE_REF
|
||||
#undef CCSTD_HASH_SPECIALIZE_TEMPLATE_REF
|
||||
|
||||
// Specializing ccstd::hash for pointers.
|
||||
|
||||
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
|
||||
template <class T>
|
||||
struct hash<T*>
|
||||
: public ccstd::hash_detail::hash_base<T*>
|
||||
{
|
||||
hash_t operator()(T* v) const
|
||||
{
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
|
||||
return ccstd::hash_value(v);
|
||||
#else
|
||||
hash_t x = static_cast<hash_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(v));
|
||||
|
||||
return x + (x >> 3);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
// For compilers without partial specialization, we define a
|
||||
// ccstd::hash for all remaining types. But hash_impl is only defined
|
||||
// for pointers in 'extensions.hpp' - so when CCSTD_HASH_NO_EXTENSIONS
|
||||
// is defined there will still be a compile error for types not supported
|
||||
// in the standard.
|
||||
|
||||
namespace hash_detail
|
||||
{
|
||||
template <bool IsPointer>
|
||||
struct hash_impl;
|
||||
|
||||
template <>
|
||||
struct hash_impl<true>
|
||||
{
|
||||
template <class T>
|
||||
struct inner
|
||||
: public ccstd::hash_detail::hash_base<T>
|
||||
{
|
||||
hash_t operator()(T val) const
|
||||
{
|
||||
#if !BOOST_WORKAROUND(__SUNPRO_CC, <= 590)
|
||||
return ccstd::hash_value(val);
|
||||
#else
|
||||
hash_t x = static_cast<hash_t>(
|
||||
reinterpret_cast<std::ptrdiff_t>(val));
|
||||
|
||||
return x + (x >> 3);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
template <class T> struct hash
|
||||
: public ccstd::hash_detail::hash_impl<ccstd::is_pointer<T>::value>
|
||||
::BOOST_NESTED_TEMPLATE inner<T>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef CCSTD_HASH_CHAR_TRAITS
|
||||
#undef CCSTD_FUNCTIONAL_HASH_ROTL32
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // CCSTD_FUNCTIONAL_HASH_HASH_HPP
|
||||
|
||||
// Include this outside of the include guards in case the file is included
|
||||
// twice - once with CCSTD_HASH_NO_EXTENSIONS defined, and then with it
|
||||
// undefined.
|
||||
|
||||
#if !defined(CCSTD_HASH_NO_EXTENSIONS) \
|
||||
&& !defined(CCSTD_FUNCTIONAL_HASH_EXTENSIONS_HPP)
|
||||
#include "base/std/hash/extensions.hpp"
|
||||
#endif
|
||||
38
cocos/base/std/hash/hash_fwd.hpp
Normal file
38
cocos/base/std/hash/hash_fwd.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Based on Peter Dimov's proposal
|
||||
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf
|
||||
// issue 6.18.
|
||||
|
||||
#if !defined(CCSTD_FUNCTIONAL_HASH_FWD_HPP)
|
||||
#define CCSTD_FUNCTIONAL_HASH_FWD_HPP
|
||||
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace ccstd
|
||||
{
|
||||
using hash_t = std::uint32_t;
|
||||
|
||||
template <class T> struct hash;
|
||||
|
||||
template <class T> void hash_combine(hash_t& seed, T const& v);
|
||||
|
||||
template <class It> hash_t hash_range(It, It);
|
||||
template <class It> void hash_range(hash_t&, It, It);
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x551))
|
||||
template <class T> inline hash_t hash_range(T*, T*);
|
||||
template <class T> inline void hash_range(hash_t&, T*, T*);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
52
cocos/base/std/optional.h
Normal file
52
cocos/base/std/optional.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_CXX_17
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
using std::nullopt;
|
||||
using std::nullopt_t;
|
||||
using std::optional;
|
||||
|
||||
}; // namespace ccstd
|
||||
#else
|
||||
#include "base/std/container/string.h"
|
||||
#include "boost/none.hpp"
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
using boost::optional;
|
||||
using nullopt_t = boost::none_t;
|
||||
|
||||
const nullopt_t nullopt((boost::none_t::init_tag())); // NOLINT // use std style
|
||||
|
||||
}; // namespace ccstd
|
||||
|
||||
#endif
|
||||
66
cocos/base/std/variant.h
Normal file
66
cocos/base/std/variant.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2021-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_CXX_17
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
using std::get;
|
||||
using std::get_if;
|
||||
using std::holds_alternative;
|
||||
using std::in_place_index;
|
||||
using std::monostate;
|
||||
using std::variant;
|
||||
using std::variant_alternative;
|
||||
using std::variant_alternative_t;
|
||||
using std::variant_size;
|
||||
using std::variant_size_v;
|
||||
using std::visit;
|
||||
|
||||
}; // namespace ccstd
|
||||
|
||||
#else
|
||||
|
||||
#include "boost/variant2/variant.hpp"
|
||||
|
||||
namespace ccstd {
|
||||
|
||||
using boost::variant2::get;
|
||||
using boost::variant2::get_if;
|
||||
using boost::variant2::holds_alternative;
|
||||
using boost::variant2::in_place_index;
|
||||
using boost::variant2::monostate;
|
||||
using boost::variant2::variant;
|
||||
using boost::variant2::variant_alternative;
|
||||
using boost::variant2::variant_alternative_t;
|
||||
using boost::variant2::variant_size;
|
||||
using boost::variant2::variant_size_v;
|
||||
using boost::variant2::visit;
|
||||
|
||||
}; // namespace ccstd
|
||||
#endif
|
||||
46
cocos/base/threading/AutoReleasePool-apple.mm
Normal file
46
cocos/base/threading/AutoReleasePool-apple.mm
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2022 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "AutoReleasePool.h"
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
|
||||
namespace cc {
|
||||
|
||||
AutoReleasePool::AutoReleasePool() {
|
||||
_nsReleasePool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
AutoReleasePool::~AutoReleasePool() {
|
||||
drain();
|
||||
}
|
||||
|
||||
void AutoReleasePool::drain() {
|
||||
if (_nsReleasePool) {
|
||||
[static_cast<NSAutoreleasePool *>(_nsReleasePool) drain];
|
||||
_nsReleasePool = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
35
cocos/base/threading/AutoReleasePool.cpp
Normal file
35
cocos/base/threading/AutoReleasePool.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "AutoReleasePool.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
AutoReleasePool::AutoReleasePool() = default;
|
||||
AutoReleasePool::~AutoReleasePool() = default;
|
||||
|
||||
void AutoReleasePool::drain() {
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
44
cocos/base/threading/AutoReleasePool.h
Normal file
44
cocos/base/threading/AutoReleasePool.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace cc {
|
||||
|
||||
class AutoReleasePool final {
|
||||
public:
|
||||
AutoReleasePool();
|
||||
AutoReleasePool(const AutoReleasePool &) = delete;
|
||||
AutoReleasePool(AutoReleasePool &&) = delete;
|
||||
~AutoReleasePool();
|
||||
AutoReleasePool &operator=(const AutoReleasePool &) = delete;
|
||||
AutoReleasePool &operator=(AutoReleasePool &&) = delete;
|
||||
|
||||
void drain();
|
||||
|
||||
private:
|
||||
void *_nsReleasePool{nullptr};
|
||||
};
|
||||
|
||||
} // namespace cc
|
||||
44
cocos/base/threading/ConditionVariable.cpp
Normal file
44
cocos/base/threading/ConditionVariable.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "ConditionVariable.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
void ConditionVariable::wait() noexcept {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_condVar.wait(lock);
|
||||
}
|
||||
|
||||
void ConditionVariable::signal() noexcept {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_condVar.notify_one();
|
||||
}
|
||||
|
||||
void ConditionVariable::signalAll() noexcept {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_condVar.notify_all();
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
54
cocos/base/threading/ConditionVariable.h
Normal file
54
cocos/base/threading/ConditionVariable.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace cc {
|
||||
|
||||
class ConditionVariable final {
|
||||
public:
|
||||
void wait() noexcept;
|
||||
template <typename Function, typename... Args>
|
||||
void wait(Function &&func, Args &&...args) noexcept;
|
||||
void signal() noexcept;
|
||||
void signalAll() noexcept;
|
||||
|
||||
private:
|
||||
std::mutex _mutex;
|
||||
std::condition_variable _condVar;
|
||||
};
|
||||
|
||||
// DO NOT MANIPULATE ANY SYCHRONIZATION PRIMITIVES INSIDE THE CALLBACK
|
||||
template <typename Function, typename... Args>
|
||||
void ConditionVariable::wait(Function &&func, Args &&...args) noexcept {
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_condVar.wait(lock, std::bind(std::forward<Function>(func), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
46
cocos/base/threading/Event.h
Normal file
46
cocos/base/threading/Event.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ConditionVariable.h"
|
||||
#include "Semaphore.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
template <typename T>
|
||||
class Event final {
|
||||
public:
|
||||
inline void wait() noexcept { _syncObject.wait(); }
|
||||
inline void signal() noexcept { _syncObject.signal(); };
|
||||
inline void signalAll() noexcept { _syncObject.signalAll(); }
|
||||
|
||||
private:
|
||||
T _syncObject{};
|
||||
};
|
||||
|
||||
using EventCV = Event<ConditionVariable>;
|
||||
using EventSem = Event<Semaphore>;
|
||||
|
||||
} // namespace cc
|
||||
321
cocos/base/threading/MessageQueue.cpp
Normal file
321
cocos/base/threading/MessageQueue.cpp
Normal file
@@ -0,0 +1,321 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#include "MessageQueue.h"
|
||||
#include "AutoReleasePool.h"
|
||||
#include "base/Utils.h"
|
||||
|
||||
namespace cc {
|
||||
|
||||
namespace {
|
||||
uint32_t constexpr MEMORY_CHUNK_POOL_CAPACITY = 64;
|
||||
uint32_t constexpr SWITCH_CHUNK_MEMORY_REQUIREMENT = sizeof(MemoryChunkSwitchMessage) + utils::ALIGN_TO<sizeof(DummyMessage), 16>;
|
||||
} // namespace
|
||||
|
||||
MessageQueue::MemoryAllocator &MessageQueue::MemoryAllocator::getInstance() noexcept {
|
||||
static MessageQueue::MemoryAllocator instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
uint8_t *MessageQueue::MemoryAllocator::request() noexcept {
|
||||
uint8_t *newChunk = nullptr;
|
||||
|
||||
if (_chunkPool.try_dequeue(newChunk)) {
|
||||
_chunkCount.fetch_sub(1, std::memory_order_acq_rel);
|
||||
} else {
|
||||
newChunk = memoryAllocateForMultiThread<uint8_t>(MEMORY_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
return newChunk;
|
||||
}
|
||||
|
||||
void MessageQueue::MemoryAllocator::recycle(uint8_t *const chunk, bool const freeByUser) noexcept {
|
||||
if (freeByUser) {
|
||||
_chunkFreeQueue.enqueue(chunk);
|
||||
} else {
|
||||
free(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueue::MemoryAllocator::freeByUser(MessageQueue *const mainMessageQueue) noexcept {
|
||||
auto *queue = &_chunkFreeQueue;
|
||||
|
||||
ENQUEUE_MESSAGE_1(
|
||||
mainMessageQueue, FreeChunksInFreeQueue,
|
||||
queue, queue,
|
||||
{
|
||||
uint8_t *chunk = nullptr;
|
||||
|
||||
while (queue->try_dequeue(chunk)) {
|
||||
MessageQueue::MemoryAllocator::getInstance().free(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
mainMessageQueue->kick();
|
||||
}
|
||||
|
||||
MessageQueue::MemoryAllocator::~MemoryAllocator() noexcept {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void MessageQueue::MemoryAllocator::destroy() noexcept {
|
||||
uint8_t *chunk = nullptr;
|
||||
if (_chunkPool.try_dequeue(chunk)) {
|
||||
::free(chunk);
|
||||
_chunkCount.fetch_sub(1, std::memory_order_acq_rel);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueue::MemoryAllocator::free(uint8_t *const chunk) noexcept {
|
||||
if (_chunkCount.load(std::memory_order_acquire) >= MEMORY_CHUNK_POOL_CAPACITY) {
|
||||
memoryFreeForMultiThread(chunk);
|
||||
} else {
|
||||
_chunkPool.enqueue(chunk);
|
||||
_chunkCount.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
}
|
||||
|
||||
MessageQueue::MessageQueue() {
|
||||
uint8_t *const chunk = MemoryAllocator::getInstance().request();
|
||||
|
||||
_writer.currentMemoryChunk = chunk;
|
||||
_reader.currentMemoryChunk = chunk;
|
||||
|
||||
// sentinel node will not be executed
|
||||
Message *const msg = allocate<DummyMessage>(1);
|
||||
pushMessages();
|
||||
pullMessages();
|
||||
_reader.lastMessage = msg;
|
||||
--_reader.newMessageCount;
|
||||
}
|
||||
|
||||
void MessageQueue::kick() noexcept {
|
||||
pushMessages();
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_condVar.notify_all();
|
||||
}
|
||||
|
||||
void MessageQueue::kickAndWait() noexcept {
|
||||
EventSem event;
|
||||
EventSem *const pEvent = &event;
|
||||
|
||||
ENQUEUE_MESSAGE_1(this, WaitUntilFinish,
|
||||
pEvent, pEvent,
|
||||
{
|
||||
pEvent->signal();
|
||||
});
|
||||
|
||||
kick();
|
||||
event.wait();
|
||||
}
|
||||
|
||||
void MessageQueue::runConsumerThread() noexcept {
|
||||
if (_immediateMode || _workerAttached) return;
|
||||
|
||||
_reader.terminateConsumerThread = false;
|
||||
_reader.flushingFinished = false;
|
||||
|
||||
_consumerThread = ccnew std::thread(&MessageQueue::consumerThreadLoop, this);
|
||||
_workerAttached = true;
|
||||
}
|
||||
|
||||
void MessageQueue::terminateConsumerThread() noexcept {
|
||||
if (_immediateMode || !_workerAttached) return;
|
||||
|
||||
EventSem event;
|
||||
EventSem *const pEvent = &event;
|
||||
|
||||
ReaderContext *const pR = &_reader;
|
||||
|
||||
ccnew_placement(allocate<TerminateConsumerThreadMessage>(1)) TerminateConsumerThreadMessage(pEvent, pR);
|
||||
|
||||
kick();
|
||||
event.wait();
|
||||
|
||||
if (_consumerThread != nullptr) {
|
||||
if (_consumerThread->joinable()) {
|
||||
_consumerThread->join();
|
||||
}
|
||||
}
|
||||
CC_SAFE_DELETE(_consumerThread);
|
||||
}
|
||||
|
||||
void MessageQueue::finishWriting() noexcept {
|
||||
if (!_immediateMode) {
|
||||
bool *const flushingFinished = &_reader.flushingFinished;
|
||||
|
||||
ENQUEUE_MESSAGE_1(this, finishWriting,
|
||||
flushingFinished, flushingFinished,
|
||||
{
|
||||
*flushingFinished = true;
|
||||
});
|
||||
|
||||
kick();
|
||||
}
|
||||
}
|
||||
|
||||
void MessageQueue::recycleMemoryChunk(uint8_t *const chunk) const noexcept {
|
||||
MessageQueue::MemoryAllocator::getInstance().recycle(chunk, _freeChunksByUser);
|
||||
}
|
||||
|
||||
void MessageQueue::freeChunksInFreeQueue(MessageQueue *const mainMessageQueue) noexcept {
|
||||
MessageQueue::MemoryAllocator::getInstance().freeByUser(mainMessageQueue);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
uint8_t *MessageQueue::allocateImpl(uint32_t allocatedSize, uint32_t const requestSize) noexcept {
|
||||
uint32_t const alignedSize = align(requestSize, 16);
|
||||
CC_ASSERT(alignedSize + SWITCH_CHUNK_MEMORY_REQUIREMENT <= MEMORY_CHUNK_SIZE);
|
||||
|
||||
uint32_t const newOffset = _writer.offset + alignedSize;
|
||||
|
||||
// newOffset contains the DummyMessage
|
||||
if (newOffset + sizeof(MemoryChunkSwitchMessage) <= MEMORY_CHUNK_SIZE) {
|
||||
uint8_t *const allocatedMemory = _writer.currentMemoryChunk + _writer.offset;
|
||||
_writer.offset = newOffset;
|
||||
return allocatedMemory;
|
||||
}
|
||||
uint8_t *const newChunk = MessageQueue::MemoryAllocator::getInstance().request();
|
||||
auto *const switchMessage = reinterpret_cast<MemoryChunkSwitchMessage *>(_writer.currentMemoryChunk + _writer.offset);
|
||||
ccnew_placement(switchMessage) MemoryChunkSwitchMessage(this, newChunk, _writer.currentMemoryChunk);
|
||||
switchMessage->_next = reinterpret_cast<Message *>(newChunk); // point to start position
|
||||
_writer.lastMessage = switchMessage;
|
||||
++_writer.pendingMessageCount;
|
||||
_writer.currentMemoryChunk = newChunk;
|
||||
_writer.offset = 0;
|
||||
|
||||
DummyMessage *const head = allocate<DummyMessage>(1);
|
||||
ccnew_placement(head) DummyMessage;
|
||||
|
||||
if (_immediateMode) {
|
||||
pushMessages();
|
||||
pullMessages();
|
||||
CC_ASSERT_EQ(_reader.newMessageCount, 2);
|
||||
executeMessages();
|
||||
executeMessages();
|
||||
}
|
||||
|
||||
return allocateImpl(allocatedSize, requestSize);
|
||||
}
|
||||
|
||||
void MessageQueue::pushMessages() noexcept {
|
||||
_writer.writtenMessageCount.fetch_add(_writer.pendingMessageCount, std::memory_order_acq_rel);
|
||||
_writer.pendingMessageCount = 0;
|
||||
}
|
||||
|
||||
void MessageQueue::pullMessages() noexcept {
|
||||
uint32_t const writtenMessageCountNew = _writer.writtenMessageCount.load(std::memory_order_acquire);
|
||||
_reader.newMessageCount += writtenMessageCountNew - _reader.writtenMessageCountSnap;
|
||||
_reader.writtenMessageCountSnap = writtenMessageCountNew;
|
||||
}
|
||||
|
||||
void MessageQueue::flushMessages() noexcept {
|
||||
while (!_reader.flushingFinished) {
|
||||
executeMessages();
|
||||
}
|
||||
|
||||
_reader.flushingFinished = false;
|
||||
}
|
||||
|
||||
void MessageQueue::executeMessages() noexcept {
|
||||
Message *const msg = readMessage();
|
||||
|
||||
if (!msg) {
|
||||
return;
|
||||
}
|
||||
|
||||
msg->execute();
|
||||
msg->~Message();
|
||||
}
|
||||
|
||||
Message *MessageQueue::readMessage() noexcept {
|
||||
while (!hasNewMessage()) { // if empty
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
pullMessages(); // try pulling data from consumer
|
||||
if (!hasNewMessage()) { // still empty
|
||||
_condVar.wait(lock); // wait for the producer to wake me up
|
||||
pullMessages(); // pulling again
|
||||
}
|
||||
}
|
||||
|
||||
Message *const msg = _reader.lastMessage->getNext();
|
||||
_reader.lastMessage = msg;
|
||||
--_reader.newMessageCount;
|
||||
CC_ASSERT(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
MessageQueue::~MessageQueue() {
|
||||
recycleMemoryChunk(_writer.currentMemoryChunk);
|
||||
}
|
||||
|
||||
void MessageQueue::consumerThreadLoop() noexcept {
|
||||
while (!_reader.terminateConsumerThread) {
|
||||
AutoReleasePool autoReleasePool;
|
||||
flushMessages();
|
||||
}
|
||||
|
||||
_workerAttached = false;
|
||||
}
|
||||
|
||||
char const *DummyMessage::getName() const noexcept {
|
||||
return "Dummy";
|
||||
}
|
||||
|
||||
MemoryChunkSwitchMessage::MemoryChunkSwitchMessage(MessageQueue *const queue, uint8_t *const newChunk, uint8_t *const oldChunk) noexcept
|
||||
: _messageQueue(queue),
|
||||
_newChunk(newChunk),
|
||||
_oldChunk(oldChunk) {
|
||||
}
|
||||
|
||||
MemoryChunkSwitchMessage::~MemoryChunkSwitchMessage() {
|
||||
_messageQueue->recycleMemoryChunk(_oldChunk);
|
||||
}
|
||||
|
||||
void MemoryChunkSwitchMessage::execute() noexcept {
|
||||
_messageQueue->_reader.currentMemoryChunk = _newChunk;
|
||||
_messageQueue->pullMessages();
|
||||
}
|
||||
|
||||
char const *MemoryChunkSwitchMessage::getName() const noexcept {
|
||||
return "MemoryChunkSwitch";
|
||||
}
|
||||
|
||||
TerminateConsumerThreadMessage::TerminateConsumerThreadMessage(EventSem *const pEvent, ReaderContext *const pR) noexcept
|
||||
: _event(pEvent),
|
||||
_reader(pR) {
|
||||
}
|
||||
|
||||
void TerminateConsumerThreadMessage::execute() noexcept {
|
||||
_reader->terminateConsumerThread = true;
|
||||
_reader->flushingFinished = true;
|
||||
_event->signal();
|
||||
}
|
||||
|
||||
char const *TerminateConsumerThreadMessage::getName() const noexcept {
|
||||
return "TerminateConsumerThread";
|
||||
}
|
||||
|
||||
} // namespace cc
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user