[add] first

This commit is contained in:
2023-10-08 10:24:48 +08:00
commit b1ae0510a9
1048 changed files with 3254361 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
#pragma once
#include <string.h>
namespace il2cpp
{
namespace utils
{
class BaselibHandleUtils
{
public:
template<typename BaselibHandleType>
static void* HandleToVoidPtr(BaselibHandleType baselibHandle)
{
// following asserts check that the handle fits into void* in its entirety
static_assert(sizeof(BaselibHandleType) <= sizeof(void*), "baselib handle does not fit void*");
static_assert(sizeof(BaselibHandleType::handle) <= sizeof(void*), "baselib handle does not fit void*");
void* result = nullptr;
memcpy(&result, &baselibHandle.handle, sizeof(result));
return result;
}
template<typename BaselibHandleType>
static BaselibHandleType VoidPtrToHandle(void* ptr)
{
static_assert(sizeof(BaselibHandleType) <= sizeof(void*), "baselib handle does not fit void*");
static_assert(sizeof(BaselibHandleType::handle) <= sizeof(void*), "baselib handle does not fit void*");
decltype(BaselibHandleType::handle)result = {};
memcpy(&result, &ptr, sizeof(ptr));
return BaselibHandleType { result };
}
};
}
}

View File

@@ -0,0 +1,47 @@
#pragma once
#include "NonCopyable.h"
#include "../os/Mutex.h"
#include "Baselib.h"
#include "Cpp/Atomic.h"
#include "Cpp/ReentrantLock.h"
namespace il2cpp
{
namespace utils
{
typedef void (*CallOnceFunc) (void* arg);
struct OnceFlag : NonCopyable
{
OnceFlag() : m_IsSet(false)
{
}
friend void CallOnce(OnceFlag& flag, CallOnceFunc func, void* arg);
bool IsSet()
{
return m_IsSet;
}
private:
baselib::atomic<bool> m_IsSet;
baselib::ReentrantLock m_Mutex;
};
inline void CallOnce(OnceFlag& flag, CallOnceFunc func, void* arg)
{
if (!flag.m_IsSet)
{
os::FastAutoLock lock(&flag.m_Mutex);
if (!flag.m_IsSet)
{
func(arg);
flag.m_IsSet = true;
}
}
}
}
}

View File

@@ -0,0 +1,256 @@
#pragma once
#include <algorithm>
#include <vector>
#include <functional>
#include "NonCopyable.h"
namespace il2cpp
{
namespace utils
{
namespace collections
{
// Memory compact, map-like data structure that stores values and
// is a able to compute the key from the value with the provided converter
// This data structure is perfect to storing values that will not be changed
// for the duration of program (like type metadata) and need fast querying
//
// It is able to store multiple values associated with a single key, and query them through find()
// find_first() is a special case find() which improves performance for cases where we don't store multiple values for each key
template<typename TKey, typename TValue, typename TValueToKeyConverter, typename TKeyLess = std::less<TKey>, typename TKeyEquals = std::equal_to<TKey> >
class ArrayValueMap : NonCopyable
{
public:
typedef ArrayValueMap<TKey, TValue, TValueToKeyConverter, TKeyLess, TKeyEquals> map_type;
typedef const TValue* iterator;
private:
const TValue* m_Values;
const size_t m_ValueCount;
bool m_OwnStorage;
const TValueToKeyConverter m_ValueToKeyConverter;
const TKeyLess m_KeyLessComparer;
const TKeyEquals m_KeyEqualsComparer;
struct SortComparer
{
private:
const TValueToKeyConverter m_ValueToKeyConverter;
const TKeyLess m_KeyComparer;
public:
SortComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
{
}
inline bool operator()(const TValue& left, const TValue& right) const
{
return m_KeyComparer(m_ValueToKeyConverter(left), m_ValueToKeyConverter(right));
}
};
struct LowerBoundFindComparer
{
private:
const TValueToKeyConverter m_ValueToKeyConverter;
const TKeyLess m_KeyComparer;
public:
LowerBoundFindComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
{
}
inline bool operator()(const TValue& left, const TKey& right) const
{
return m_KeyComparer(m_ValueToKeyConverter(left), right);
}
};
struct UpperBoundFindComparer
{
private:
const TValueToKeyConverter m_ValueToKeyConverter;
const TKeyLess m_KeyComparer;
public:
UpperBoundFindComparer(TValueToKeyConverter valueToKeyConverter, TKeyLess keyComparer) :
m_ValueToKeyConverter(valueToKeyConverter), m_KeyComparer(keyComparer)
{
}
inline bool operator()(const TKey& left, const TValue& right) const
{
return m_KeyComparer(left, m_ValueToKeyConverter(right));
}
};
inline static TValue* InitializeInPlace(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter, TKeyLess keyLessComparer)
{
std::sort(values, values + valueCount, SortComparer(valueToKeyConverter, keyLessComparer));
return values;
}
inline static TValue* AllocateAndInitialize(const TValue* originalValues, size_t valueCount, TValueToKeyConverter valueToKeyConverter, TKeyLess keyLessComparer)
{
TValue* values = new TValue[valueCount];
memcpy(values, originalValues, valueCount * sizeof(TValue));
return InitializeInPlace(values, valueCount, valueToKeyConverter, keyLessComparer);
}
public:
inline ArrayValueMap() :
m_Values(NULL),
m_ValueCount(0),
m_OwnStorage(false),
m_ValueToKeyConverter(TValueToKeyConverter()),
m_KeyLessComparer(TKeyLess()),
m_KeyEqualsComparer(TKeyEquals())
{
}
// Non-allocating constructor. It will take a pointer and will not allocate any storage
// It WILL sort existing values
inline ArrayValueMap(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals()) :
m_Values(InitializeInPlace(values, valueCount, valueToKeyConverter, keyLessComparer)),
m_ValueCount(valueCount),
m_ValueToKeyConverter(valueToKeyConverter),
m_KeyLessComparer(keyLessComparer),
m_KeyEqualsComparer(keyEqualsComparer),
m_OwnStorage(false)
{
}
// Allocating constructor
// Will copy values to newly allocated storage
inline ArrayValueMap(const std::vector<TValue>& values, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals()) :
m_Values(AllocateAndInitialize(values.data(), values.size(), valueToKeyConverter, keyLessComparer)),
m_ValueCount(values.size()),
m_ValueToKeyConverter(valueToKeyConverter),
m_KeyLessComparer(keyLessComparer),
m_KeyEqualsComparer(keyEqualsComparer),
m_OwnStorage(true)
{
}
~ArrayValueMap()
{
if (m_OwnStorage)
{
delete[] m_Values;
}
}
inline void assign_external(TValue* values, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
{
this->~ArrayValueMap();
new(this) map_type(values, valueCount, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
}
// Constructs map that contains pointers to original array
inline void assign_addresses(const TValue& valueArray, size_t valueCount, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
{
this->~ArrayValueMap();
TValue* storage = NULL;
if (valueCount > 0)
{
storage = new TValue[valueCount];
for (size_t i = 0; i < valueCount; i++)
{
storage[i] = &valueArray[i];
}
}
new(this) map_type(storage, valueCount, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
m_OwnStorage = true;
}
inline void assign(const std::vector<TValue>& values, TValueToKeyConverter valueToKeyConverter = TValueToKeyConverter(),
TKeyLess keyLessComparer = TKeyLess(), TKeyEquals keyEqualsComparer = TKeyEquals())
{
this->~ArrayValueMap();
new(this) map_type(values, valueToKeyConverter, keyLessComparer, keyEqualsComparer);
}
inline iterator begin() const
{
return m_Values;
}
inline iterator end() const
{
return m_Values + m_ValueCount;
}
template<typename EqualsPredicate>
inline iterator find(const TKey& key, const EqualsPredicate& equalsPredicate) const
{
iterator dataStart = begin();
iterator dataEnd = end();
iterator ptr = std::lower_bound(dataStart, dataEnd, key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
for (; ptr != dataEnd && m_KeyEqualsComparer(m_ValueToKeyConverter(*ptr), key); ptr++)
{
if (equalsPredicate(*ptr))
return ptr;
}
return dataEnd;
}
inline iterator find_first(const TKey& key) const
{
iterator dataStart = begin();
iterator dataEnd = end();
iterator ptr = std::lower_bound(dataStart, dataEnd, key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
if (ptr != dataEnd && m_KeyEqualsComparer(m_ValueToKeyConverter(*ptr), key))
return ptr;
return dataEnd;
}
inline iterator lower_bound(const TKey& key) const
{
return std::lower_bound(begin(), end(), key, LowerBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
}
inline iterator upper_bound(const TKey& key) const
{
return std::upper_bound(begin(), end(), key, UpperBoundFindComparer(m_ValueToKeyConverter, m_KeyLessComparer));
}
inline size_t size() const
{
return m_ValueCount;
}
inline const TValue& operator[](size_t i) const
{
return m_Values[i];
}
template<typename Mutator>
inline void mutate(Mutator& mutator)
{
size_t count = m_ValueCount;
const TValue* values = m_Values;
for (size_t i = 0; i < count; i++)
mutator(const_cast<TValue*>(values + i));
m_Values = InitializeInPlace(const_cast<TValue*>(values), count, m_ValueToKeyConverter, m_KeyLessComparer);
}
};
}
} // namespace utils
} // namespace il2cpp

View File

@@ -0,0 +1,13 @@
#pragma once
#include <string>
namespace il2cpp
{
namespace utils
{
bool Match(const std::string name, size_t nameIndex, const std::string& pattern, const size_t patternIndex);
bool Match(const std::string name, const std::string& pattern);
std::string CollapseAdjacentStars(const std::string& pattern);
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include <vector>
#include "il2cpp-config.h"
#include "il2cpp-string-types.h"
struct Il2CppDomain;
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API Environment
{
public:
static const std::vector<UTF16String>& GetMainArgs();
static int GetNumMainArgs();
static void SetMainArgs(const char* const* args, int num_args);
static void SetMainArgs(const Il2CppChar* const* args, int num_args);
};
} /* namespace vm */
} /* namespace il2cpp */

View File

@@ -0,0 +1,22 @@
#pragma once
#include "il2cpp-config.h"
#include <string>
struct Il2CppException;
#include "Baselib.h"
#include "C/Baselib_ErrorState.h"
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API Exception
{
public:
static std::string FormatException(const Il2CppException* ex);
static std::string FormatStackTrace(const Il2CppException* ex);
static std::string FormatInvalidCastException(const Il2CppClass* fromType, const Il2CppClass* toType);
static std::string FormatBaselibErrorState(const Baselib_ErrorState& errorState);
};
} // utils
} // utils

View File

@@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
namespace il2cpp
{
namespace utils
{
template<typename T, int Size>
class ExceptionSupportStack
{
public:
ExceptionSupportStack() : m_count(0)
{
}
void push(T value)
{
// This function is rather unsafe. We don't track the size of storage,
// and assume the caller will not push more values than it has allocated.
// This function should only be used from generated code, where
// we control the calls to this function.
IL2CPP_ASSERT(m_count < Size);
m_Storage[m_count] = value;
m_count++;
}
void pop()
{
IL2CPP_ASSERT(!empty());
m_count--;
}
T top() const
{
IL2CPP_ASSERT(!empty());
return m_Storage[m_count - 1];
}
bool empty() const
{
return m_count == 0;
}
private:
T m_Storage[Size];
int m_count;
};
}
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include "il2cpp-config.h"
#include "utils/Il2CppError.h"
namespace il2cpp
{
namespace utils
{
template<typename T>
class Expected
{
public:
Expected(const T& result) : m_Result(result) {}
Expected(const Il2CppError& error) : m_Error(error) {}
bool HasError() const
{
return m_Error.GetErrorCode() != NoError;
}
Il2CppError GetError() const
{
return m_Error;
}
T& Get()
{
IL2CPP_ASSERT(!HasError());
return m_Result;
}
const T& Get() const
{
IL2CPP_ASSERT(!HasError());
return m_Result;
}
private:
T m_Result;
const Il2CppError m_Error;
Expected() {}
};
} // namespace il2cpp
} // namespace utils

View File

@@ -0,0 +1,98 @@
#pragma once
#if defined(__x86_64__) || defined(_M_X64)
# include <emmintrin.h>
/// atomic_word must be 8 bytes aligned if you want to use it with atomic_* ops.
# if defined(_MSC_VER)
typedef __int64 atomic_word;
# else
typedef long long atomic_word;
# endif
/// atomic_word2 must be 16 bytes aligned if you want to use it with atomic_* ops.
union atomic_word2
{
__m128i v;
struct
{
atomic_word lo, hi;
};
};
#define IL2CPP_ATOMIC_HAS_QUEUE
#elif defined(__x86__) || defined(__i386__) || defined(_M_IX86)
/// atomic_word must be 4 bytes aligned if you want to use it with atomic_* ops.
typedef int atomic_word;
/// atomic_word2 must be 8 bytes aligned if you want to use it with atomic_* ops.
union atomic_word2
{
# if defined(_MSC_VER)
__int64 v;
# else
long long v;
# endif
# if !defined(__SSE2__)
double d;
# endif
struct
{
atomic_word lo, hi;
};
};
#define IL2CPP_ATOMIC_HAS_QUEUE
#elif defined(_M_ARM64) || (defined(__arm64__) || defined(__aarch64__)) && (defined(__clang__) || defined(__GNUC__))
typedef long long atomic_word;
struct alignas(16) atomic_word2
{
atomic_word lo;
atomic_word hi;
};
#define IL2CPP_ATOMIC_HAS_QUEUE
#elif defined(_M_ARM) || (defined(__arm__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)) && (defined(__clang__) || defined(__GNUC__)))
typedef int atomic_word;
union atomic_word2
{
# if defined(_MSC_VER)
__int64 v;
# else
long long v;
# endif
struct
{
atomic_word lo;
atomic_word hi;
};
};
#define IL2CPP_ATOMIC_HAS_QUEUE
#elif defined(__EMSCRIPTEN__)
#include <stdint.h>
typedef int32_t atomic_word;
union atomic_word2
{
int64_t v;
struct
{
atomic_word lo;
atomic_word hi;
};
};
#else
#error There is no atomic_word implementation for this platform.
#endif

View File

@@ -0,0 +1,41 @@
#pragma once
#include "utils/NonCopyable.h"
namespace il2cpp
{
namespace utils
{
namespace functional
{
struct TrueFilter
{
template<typename T>
inline bool operator()(const T& item) const
{
return true;
}
};
template<typename ItemType, typename Comparer>
struct Filter : NonCopyable
{
private:
ItemType m_Item;
Comparer m_Comparer;
public:
Filter(ItemType item, Comparer comparer = Comparer()) :
m_Item(item), m_Comparer(comparer)
{
}
template<typename T>
inline bool operator()(const T& item) const
{
return m_Comparer(m_Item, item);
}
};
} // functional
} // utils
} // il2cpp

View File

@@ -0,0 +1,40 @@
#pragma once
namespace il2cpp
{
namespace utils
{
class HashUtils
{
static const size_t Seed = 486187739;
public:
static inline size_t Combine(size_t hash1, size_t hash2)
{
return hash1 * Seed + hash2;
}
static inline size_t AlignedPointerHash(const void* ptr)
{
return ((uintptr_t)ptr) >> 3;
}
};
template<class T>
struct PointerHash
{
size_t operator()(const T* value) const
{
return (size_t)value;
}
};
template<class T>
struct PassThroughHash
{
size_t operator()(T value) const
{
return (size_t)value;
}
};
} /* namespace vm */
} /* namespace il2cpp */

View File

@@ -0,0 +1,35 @@
#pragma once
#include "il2cpp-config.h"
#include <string>
namespace il2cpp
{
namespace utils
{
enum Il2CppErrorCode
{
NoError,
NotSupported,
ComError,
UnauthorizedAccess,
};
class Il2CppError
{
public:
Il2CppError();
Il2CppError(Il2CppErrorCode errorCode, const char* message);
Il2CppError(Il2CppErrorCode errorCode, il2cpp_hresult_t hr);
Il2CppErrorCode GetErrorCode() const;
std::string GetErrorMessage() const;
il2cpp_hresult_t GetHr() const;
bool GetDefaultToCOMException() const;
private:
const Il2CppErrorCode m_ErrorCode;
const std::string m_Message;
const il2cpp_hresult_t m_Hr;
};
} // namespace utils
} // namespace error

View File

@@ -0,0 +1,135 @@
#pragma once
// Mono code also has define for GROUP_SIZE, so we need to wrap its usage here
#pragma push_macro("GROUP_SIZE")
#undef GROUP_SIZE
#if IL2CPP_USE_SPARSEHASH
#include "../../external/google/sparsehash/sparse_hash_map.h"
#else
#include "../../external/google/sparsehash/dense_hash_map.h"
#endif
#pragma pop_macro("GROUP_SIZE")
#include "KeyWrapper.h"
#include "os/FastReaderReaderWriterLock.h"
template<class Key, class T,
class HashFcn = SPARSEHASH_HASH<Key>,
class EqualKey = std::equal_to<Key>,
class Alloc = GOOGLE_NAMESPACE::libc_allocator_with_realloc<std::pair<const KeyWrapper<Key>, T> > >
#if IL2CPP_USE_SPARSEHASH
class Il2CppHashMap : public GOOGLE_NAMESPACE::sparse_hash_map<KeyWrapper<Key>, T, HashFcn, typename KeyWrapper<Key>::template EqualsComparer<EqualKey>, Alloc>
#else
class Il2CppHashMap : public GOOGLE_NAMESPACE::dense_hash_map<KeyWrapper<Key>, T, HashFcn, typename KeyWrapper<Key>::template EqualsComparer<EqualKey>, Alloc>
#endif
{
private:
#if IL2CPP_USE_SPARSEHASH
typedef GOOGLE_NAMESPACE::sparse_hash_map<KeyWrapper<Key>, T, HashFcn, typename KeyWrapper<Key>::template EqualsComparer<EqualKey>, Alloc> Base;
#else
typedef GOOGLE_NAMESPACE::dense_hash_map<KeyWrapper<Key>, T, HashFcn, typename KeyWrapper<Key>::template EqualsComparer<EqualKey>, Alloc> Base;
#endif
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::key_type key_type;
explicit Il2CppHashMap(size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
Base(n, hf, key_equal(eql))
{
Base::set_deleted_key(key_type(key_type::KeyType_Deleted));
#if !IL2CPP_USE_SPARSEHASH
Base::set_empty_key(key_type(key_type::KeyType_Empty));
#endif
}
template<class InputIterator>
Il2CppHashMap(InputIterator f, InputIterator l,
size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
Base(f, l, n, hf, key_equal(eql))
{
Base::set_deleted_key(key_type(key_type::KeyType_Deleted));
#if !IL2CPP_USE_SPARSEHASH
Base::set_empty_key(key_type(key_type::KeyType_Empty));
#endif
}
void add(const key_type& key, const T& value)
{
Base::insert(std::make_pair(key, value));
}
};
template<class Key, class T,
class HashFcn = SPARSEHASH_HASH<Key>,
class EqualKey = std::equal_to<Key>,
class Alloc = GOOGLE_NAMESPACE::libc_allocator_with_realloc<std::pair<const KeyWrapper<Key>, T> > >
class Il2CppReaderWriterLockedHashMap
{
public:
typedef typename Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc>::key_type key_type;
typedef typename Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc>::size_type size_type;
typedef typename Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc>::const_iterator const_iterator;
typedef typename Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc>::iterator iterator;
typedef typename Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc>::hasher hasher;
explicit Il2CppReaderWriterLockedHashMap(size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
hashMap(n, hf, eql)
{
}
bool TryGet(const key_type& key, T* value)
{
il2cpp::os::FastReaderReaderWriterAutoSharedLock readerLock(&lock);
const_iterator iter = hashMap.find(key);
if (iter != hashMap.end())
{
*value = iter->second;
return true;
}
return false;
}
bool Add(const key_type& key, const T& value)
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
return hashMap.insert(std::make_pair(key, value)).second;
}
void Clear()
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
hashMap.clear();
}
void Remove(const key_type& key)
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock readerLock(&lock);
hashMap.erase(key);
}
// This function takes no locks, some other lock must be used to protect accesses
iterator UnlockedBegin()
{
return hashMap.begin();
}
// This function takes no locks, some other lock must be used to protect accesses
iterator UnlockedEnd()
{
return hashMap.end();
}
private:
il2cpp::os::FastReaderReaderWriterLock lock;
Il2CppHashMap<Key, T, HashFcn, EqualKey, Alloc> hashMap;
};

View File

@@ -0,0 +1,126 @@
#pragma once
// Mono code also has define for GROUP_SIZE, so we need to wrap its usage here
#pragma push_macro("GROUP_SIZE")
#undef GROUP_SIZE
#if IL2CPP_USE_SPARSEHASH
#include "../../external/google/sparsehash/sparse_hash_set.h"
#else
#include "../../external/google/sparsehash/dense_hash_set.h"
#endif
#pragma pop_macro("GROUP_SIZE")
#include "KeyWrapper.h"
#include "os/FastReaderReaderWriterLock.h"
template<class Value,
class HashFcn = SPARSEHASH_HASH<Value>,
class EqualKey = std::equal_to<Value>,
class Alloc = GOOGLE_NAMESPACE::libc_allocator_with_realloc<KeyWrapper<Value> > >
#if IL2CPP_USE_SPARSEHASH
class Il2CppHashSet : public GOOGLE_NAMESPACE::sparse_hash_set<KeyWrapper<Value>, HashFcn, typename KeyWrapper<Value>::template EqualsComparer<EqualKey>, Alloc>
#else
class Il2CppHashSet : public GOOGLE_NAMESPACE::dense_hash_set<KeyWrapper<Value>, HashFcn, typename KeyWrapper<Value>::template EqualsComparer<EqualKey>, Alloc>
#endif
{
private:
#if IL2CPP_USE_SPARSEHASH
typedef GOOGLE_NAMESPACE::sparse_hash_set<KeyWrapper<Value>, HashFcn, typename KeyWrapper<Value>::template EqualsComparer<EqualKey>, Alloc> Base;
#else
typedef GOOGLE_NAMESPACE::dense_hash_set<KeyWrapper<Value>, HashFcn, typename KeyWrapper<Value>::template EqualsComparer<EqualKey>, Alloc> Base;
#endif
public:
typedef typename Base::size_type size_type;
typedef typename Base::hasher hasher;
typedef typename Base::key_equal key_equal;
typedef typename Base::key_type key_type;
explicit Il2CppHashSet(size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
Base(n, hf, key_equal(eql))
{
Base::set_deleted_key(key_type(key_type::KeyType_Deleted));
#if !IL2CPP_USE_SPARSEHASH
Base::set_empty_key(key_type(key_type::KeyType_Empty));
#endif
}
template<class InputIterator>
Il2CppHashSet(InputIterator f, InputIterator l,
size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
Base(f, l, n, hf, key_equal(eql))
{
Base::set_deleted_key(key_type(key_type::KeyType_Deleted));
#if !IL2CPP_USE_SPARSEHASH
Base::set_empty_key(key_type(key_type::KeyType_Empty));
#endif
}
};
template<class Value,
class HashFcn = SPARSEHASH_HASH<Value>,
class EqualKey = std::equal_to<Value>,
class Alloc = GOOGLE_NAMESPACE::libc_allocator_with_realloc<KeyWrapper<Value> > >
class Il2CppReaderWriterLockedHashSet
{
public:
typedef typename Il2CppHashSet<Value, HashFcn, EqualKey, Alloc>::key_type key_type;
typedef typename Il2CppHashSet<Value, HashFcn, EqualKey, Alloc>::size_type size_type;
typedef typename Il2CppHashSet<Value, HashFcn, EqualKey, Alloc>::const_iterator const_iterator;
typedef typename Il2CppHashSet<Value, HashFcn, EqualKey, Alloc>::iterator iterator;
typedef typename Il2CppHashSet<Value, HashFcn, EqualKey, Alloc>::hasher hasher;
explicit Il2CppReaderWriterLockedHashSet(size_type n = 0,
const hasher& hf = hasher(),
const EqualKey& eql = EqualKey()) :
hashSet(n, hf, eql)
{
}
bool TryGet(const Value& findValue, Value* value)
{
il2cpp::os::FastReaderReaderWriterAutoSharedLock readerLock(&lock);
const_iterator iter = hashSet.find(findValue);
if (iter != hashSet.end())
{
*value = *iter;
return true;
}
return false;
}
bool Add(const Value& value)
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
return hashSet.insert(value).second;
}
Value GetOrAdd(const Value& value)
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
auto inserted = hashSet.insert(value);
if (inserted.second)
return value;
return *(inserted.first);
}
void Clear()
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
hashSet.clear();
}
void Resize(size_t size)
{
il2cpp::os::FastReaderReaderWriterAutoExclusiveLock writerLock(&lock);
hashSet.resize(size);
}
private:
il2cpp::os::FastReaderReaderWriterLock lock;
Il2CppHashSet<Value, HashFcn, EqualKey, Alloc> hashSet;
};

View File

@@ -0,0 +1,44 @@
#pragma once
template<class T>
struct KeyWrapper
{
typedef T wrapped_type;
typedef KeyWrapper<T> self_type;
enum KeyTypeEnum { KeyType_Normal, KeyType_Empty, KeyType_Deleted };
KeyTypeEnum type;
T key;
KeyWrapper() : type(KeyType_Normal), key(T()) {}
KeyWrapper(KeyTypeEnum type_) : type(type_), key(T()) {}
KeyWrapper(const T& key_) : key(key_), type(KeyType_Normal) {}
KeyWrapper(const self_type& other) : type(other.type), key(other.key) {}
operator const T&() const { return key; }
bool isNormal() const { return (type == KeyType_Normal); }
template<typename KeyComparer>
struct EqualsComparer
{
EqualsComparer(KeyComparer keyComparer) :
m_KeyComparer(keyComparer)
{
}
bool operator()(const KeyWrapper<T>& left, const KeyWrapper<T>& right) const
{
if (left.type != right.type)
return false;
if (!left.isNormal())
return true;
return m_KeyComparer(left.key, right.key);
}
private:
KeyComparer m_KeyComparer;
};
};

View File

@@ -0,0 +1,20 @@
#pragma once
#include "il2cpp-config.h"
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API Logging
{
public:
static void Write(const char* format, ...);
static void SetLogCallback(Il2CppLogCallback method);
static bool IsLogCallbackSet();
private:
static Il2CppLogCallback s_Callback;
};
}
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "il2cpp-config.h"
struct Il2CppInteropData;
namespace il2cpp
{
namespace utils
{
class MarshalingUtils
{
public:
static void MarshalStructToNative(void* managedStructure, void* marshaledStructure, const Il2CppInteropData* interopData);
static void MarshalStructFromNative(void* marshaledStructure, void* managedStructure, const Il2CppInteropData* interopData);
static bool MarshalFreeStruct(void* marshaledStructure, const Il2CppInteropData* interopData);
};
} // namespace utils
} // namespace il2cpp

View File

@@ -0,0 +1,115 @@
#pragma once
#include "il2cpp-config.h"
#include <cmath>
#include <limits>
#include <stdint.h>
namespace il2cpp
{
namespace utils
{
namespace MathUtils
{
// Do math on low/high part separately as 64-bit integers because otherwise
// we might easily overflow during initial multiplication
inline int64_t A_Times_B_DividedBy_C(int64_t multiplicand, int64_t multiplier, int64_t divisor)
{
IL2CPP_ASSERT((llabs(divisor) & (1LL << 62)) == 0 && "Can't divide by numbers with absolute value larger than 2^62 - 1.");
bool resultIsNegative = static_cast<uint64_t>(multiplicand ^ multiplier ^ divisor) >> 63; // Result is negative if odd number of operands are negative
multiplicand = llabs(multiplicand);
IL2CPP_ASSERT(multiplicand > 0 && "Can't multiply by -2^63.");
multiplier = llabs(multiplier);
IL2CPP_ASSERT(multiplier > 0 && "Can't multiply by -2^63.");
divisor = llabs(divisor); // We already asserted on divisor size
uint64_t multiplicand_low = multiplicand & 0xFFFFFFFF;
uint64_t multiplicand_high = multiplicand >> 32;
uint64_t multiplier_low = multiplier & 0xFFFFFFFF;
uint64_t multiplier_high = multiplier >> 32;
// We're gonna assume our multiplicated value is 128-bit integer
// so we're gonna compose it of two uint64_t's
// a * b =
// (a_high * 2^32 + a_low) * (b_high * 2^32 + b_low) =
// a_high * b_high * 2^64 + (a_high * b_low + a_low * b_high) * 2^32 + a_low * b_low
uint64_t dividends[2] =
{
multiplicand_low * multiplier_low, // low part, bits [0, 63]
multiplicand_high * multiplier_high // high part, bits [64, 127]
};
uint64_t resultMid1 = multiplicand_high * multiplier_low + multiplicand_low * multiplier_high; // mid part, bits [32, 95]
dividends[1] += resultMid1 >> 32; // add the higher bits of mid part ([64, 95]) to high part
resultMid1 = (resultMid1 & 0xFFFFFFFF) << 32; // Now this contains the lower bits of mid part ([32, 63])
// Check for lower part overflow below adding the lower bits of mid part to it
// Add carry to high part if overflow occurs
if (dividends[0] > std::numeric_limits<uint64_t>::max() - resultMid1)
dividends[1]++;
dividends[0] += resultMid1; // add the lower bits of mid part to low part
// At this point, we got our whole divident 128-bit value inside 'dividends'
uint64_t workValue = 0; // Value that we're gonna be dividing
uint64_t result = 0; // The final result
const uint64_t kOne = 1;
int bitIndex = 127; // Current bit that we're gonna be add to the workValue
// Let's find the starting point for our division
// We'll keep adding bits from our divident to the workValue until it's higher than the divisor
// We did divisor = llabs(divisor) earlier, so cast to unsigned is safe
while (workValue < static_cast<uint64_t>(divisor))
{
workValue <<= 1;
if (bitIndex > -1)
{
workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
}
else
{
return 0;
}
bitIndex--;
}
// Main division loop
for (; bitIndex > -2 || workValue >= static_cast<uint64_t>(divisor); bitIndex--)
{
result <<= 1; // Shift result left
// Since it's binary, the division result can be only 0 and 1
// It's 1 if workValue is higher or equal to divisor
if (workValue >= static_cast<uint64_t>(divisor))
{
workValue -= static_cast<uint64_t>(divisor);
result++;
}
// Shift work value to the left and append the next bit of our dividend
IL2CPP_ASSERT((workValue & (1LL << 63)) == 0 && "overflow!");
if (bitIndex > -1)
{
workValue <<= 1;
workValue |= (dividends[bitIndex / 64] & (kOne << (bitIndex % 64))) != 0;
}
}
// Negate result if it's supposed to be negative
if (resultIsNegative)
return -static_cast<int64_t>(result);
return result;
}
}
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include "il2cpp-config.h"
namespace il2cpp
{
namespace utils
{
struct LIBIL2CPP_CODEGEN_API Memory
{
static void SetMemoryCallbacks(Il2CppMemoryCallbacks* callbacks);
static void* Malloc(size_t size);
static void* AlignedMalloc(size_t size, size_t alignment);
static void Free(void* memory);
static void AlignedFree(void* memory);
static void* Calloc(size_t count, size_t size);
static void* Realloc(void* memory, size_t newSize);
static void* AlignedRealloc(void* memory, size_t newSize, size_t alignment);
};
} /* namespace utils */
} /* namespace il2cpp */
#define IL2CPP_MALLOC(size) il2cpp::utils::Memory::Malloc(size)
#define IL2CPP_MALLOC_ALIGNED(size, alignment) il2cpp::utils::Memory::AlignedMalloc(size, alignment)
#define IL2CPP_MALLOC_ZERO(size) il2cpp::utils::Memory::Calloc(1,size)
#define IL2CPP_FREE(memory) il2cpp::utils::Memory::Free(memory)
#define IL2CPP_FREE_ALIGNED(memory) il2cpp::utils::Memory::AlignedFree(memory)
#define IL2CPP_CALLOC(count, size) il2cpp::utils::Memory::Calloc(count,size)
#define IL2CPP_REALLOC(memory, newSize) il2cpp::utils::Memory::Realloc(memory,newSize)
#define IL2CPP_REALLOC_ALIGNED(memory, newSize, alignment) il2cpp::utils::Memory::AlignedRealloc(memory, newSize, alignment)

View File

@@ -0,0 +1,22 @@
#pragma once
#include <map>
#include "os/File.h"
#include "os/Mutex.h"
#include "os/MemoryMappedFile.h"
namespace il2cpp
{
namespace utils
{
class MemoryMappedFile
{
public:
static void* Map(os::FileHandle* file);
static void* Map(os::FileHandle* file, int64_t length, int64_t offset);
static void* Map(os::FileHandle* file, int64_t length, int64_t offset, int32_t access);
static bool Unmap(void* address);
static bool Unmap(void* address, int64_t length);
};
}
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <list>
namespace il2cpp
{
namespace utils
{
class MemoryPool
{
public:
MemoryPool();
MemoryPool(size_t initialSize);
~MemoryPool();
void* Malloc(size_t size);
void* Calloc(size_t count, size_t size);
private:
struct Region;
typedef std::list<Region*> RegionList;
Region* AddRegion(size_t size);
RegionList m_Regions;
};
} /* namespace utils */
} /* namespace il2cpp */

View File

@@ -0,0 +1,29 @@
#pragma once
#include "il2cpp-config.h"
#if !IL2CPP_SANITIZE_ADDRESS
#error MemoryPoolAddressSanitizer should only be used when the address sanitizer is enabled
#endif
#include <vector>
namespace il2cpp
{
namespace utils
{
// Use system allocators with the address sanitizer, so that it can catch
// problems with memory access that might happen when our memory pool is
// used incorrectly.
class MemoryPoolAddressSanitizer
{
public:
MemoryPoolAddressSanitizer();
MemoryPoolAddressSanitizer(size_t initialSize);
~MemoryPoolAddressSanitizer();
void* Malloc(size_t size);
void* Calloc(size_t count, size_t size);
private:
std::vector<void*> m_Allocations;
};
} /* namespace utils */
} /* namespace il2cpp */

View File

@@ -0,0 +1,31 @@
#pragma once
#include <stdint.h>
#include <memory.h>
#include "il2cpp-api-types.h"
// unaligned safe reading
namespace il2cpp
{
namespace utils
{
static inline Il2CppChar ReadChar(const char* p) { Il2CppChar val; memcpy(&val, p, sizeof(Il2CppChar)); return val; }
static inline uint16_t Read16(const char* p) { uint16_t val; memcpy(&val, p, sizeof(uint16_t)); return val; }
static inline uint32_t Read32(const char* p) { uint32_t val; memcpy(&val, p, sizeof(uint32_t)); return val; }
static inline uint64_t Read64(const char* p) { uint64_t val; memcpy(&val, p, sizeof(uint64_t)); return val; }
static inline float ReadFloat(const char* p) { float val; memcpy(&val, p, sizeof(float)); return val; }
static inline double ReadDouble(const char* p) { double val; memcpy(&val, p, sizeof(double)); return val; }
static inline Il2CppChar ReadChar(const char** p) { Il2CppChar val; memcpy(&val, *p, sizeof(Il2CppChar)); *p += sizeof(Il2CppChar); return val; }
static inline uint8_t Read8(const char** p) { uint8_t val; memcpy(&val, *p, sizeof(uint8_t)); *p += sizeof(uint8_t); return val; }
static inline uint16_t Read16(const char** p) { uint16_t val; memcpy(&val, *p, sizeof(uint16_t)); *p += sizeof(uint16_t); return val; }
static inline uint32_t Read32(const char** p) { uint32_t val; memcpy(&val, *p, sizeof(uint32_t)); *p += sizeof(uint32_t); return val; }
static inline uint64_t Read64(const char** p) { uint64_t val; memcpy(&val, *p, sizeof(uint64_t)); *p += sizeof(uint64_t); return val; }
static inline float ReadFloat(const char** p) { float val; memcpy(&val, *p, sizeof(float)); *p += sizeof(float); return val; }
static inline double ReadDouble(const char** p) { double val; memcpy(&val, *p, sizeof(double)); *p += sizeof(double); return val; }
uint32_t ReadCompressedUInt32(const char** p);
int32_t ReadCompressedInt32(const char** p);
} /* utils */
} /* il2cpp */

View File

@@ -0,0 +1,55 @@
#pragma once
#include <stdint.h>
#include "xxhash.h"
namespace il2cpp
{
namespace utils
{
class MemoryUtils
{
public:
template<typename T>
static int32_t MemCmpRef(T* left, T* right)
{
return memcmp(left, right, sizeof(T));
}
#if IL2CPP_TINY
template<typename T>
static int32_t MemHashRef(T* val)
{
return XXH32(val, sizeof(T), 0x8f37154b);
}
#endif
};
#define DECL_MEMCMP_NUM(typ) template<> inline int32_t MemoryUtils::MemCmpRef<typ>(typ* left, typ* right) { return (*right > *left) ? -1 : (*right < *left) ? 1 : 0; }
DECL_MEMCMP_NUM(int8_t)
DECL_MEMCMP_NUM(int16_t)
DECL_MEMCMP_NUM(int32_t)
DECL_MEMCMP_NUM(int64_t)
DECL_MEMCMP_NUM(uint8_t)
DECL_MEMCMP_NUM(uint16_t)
DECL_MEMCMP_NUM(uint32_t)
DECL_MEMCMP_NUM(uint64_t)
// don't think this will give the right result for NaNs and such
DECL_MEMCMP_NUM(float)
DECL_MEMCMP_NUM(double)
#undef DECL_MEMCMP_NUM
#define DECL_MEMHASH_NUM(typ) template<> inline int32_t MemoryUtils::MemHashRef(typ* val) { return (int32_t)(*val); }
DECL_MEMHASH_NUM(int8_t)
DECL_MEMHASH_NUM(int16_t)
DECL_MEMHASH_NUM(int32_t)
DECL_MEMHASH_NUM(uint8_t)
DECL_MEMHASH_NUM(uint16_t)
DECL_MEMHASH_NUM(uint32_t)
DECL_MEMHASH_NUM(float)
#undef DECL_MEMHASH_NUM
template<> inline int32_t MemoryUtils::MemHashRef(int64_t* val) { int64_t k = *val; return (int32_t)(k & 0xffffffff) ^ (int32_t)((k >> 32) & 0xffffffff); }
template<> inline int32_t MemoryUtils::MemHashRef(uint64_t* val) { return MemHashRef(reinterpret_cast<int64_t*>(val)); }
template<> inline int32_t MemoryUtils::MemHashRef(double* val) { return MemHashRef(reinterpret_cast<int64_t*>(val)); }
} // namespace utils
} // namespace il2cpp

View File

@@ -0,0 +1,34 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE
#include <malloc.h>
#else
#include <stdlib.h>
#endif
#include <new>
inline void* operator new(size_t size, int alignment)
{
void* result = NULL;
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE
result = _aligned_malloc(size, alignment);
#elif IL2CPP_TARGET_ANDROID || IL2CPP_TARGET_PSP2
result = memalign(alignment, size);
#else
if (posix_memalign(&result, size, alignment))
result = NULL;
#endif
if (!result)
throw std::bad_alloc();
return result;
}
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE // Visual C++ warns if new is overridden but delete is not.
inline void operator delete(void* ptr, int alignment) throw ()
{
free(ptr);
}
#endif

View File

@@ -0,0 +1,17 @@
#pragma once
namespace il2cpp
{
namespace utils
{
class NonCopyable
{
public:
NonCopyable() {}
private:
NonCopyable(const NonCopyable&);
NonCopyable& operator=(const NonCopyable&);
};
}
}

View File

@@ -0,0 +1,18 @@
#pragma once
#include "il2cpp-config.h"
struct Il2CppString;
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API Output
{
public:
static void WriteToStdout(const char* message);
static void WriteToStderr(const char* message);
};
}
}

View File

@@ -0,0 +1,90 @@
#pragma once
#include "il2cpp-config.h"
#include <string>
#include "StringViewUtils.h"
namespace il2cpp
{
namespace utils
{
namespace PathUtils
{
std::string BasenameNoExtension(const std::string& path);
std::string PathNoExtension(const std::string& path);
template<typename CharType>
std::basic_string<CharType> Basename(const utils::StringView<CharType>& path)
{
if (path.IsEmpty())
return std::basic_string<CharType>(1, static_cast<CharType>('.'));
const size_t pos = path.RFind(IL2CPP_DIR_SEPARATOR);
// No seperators. Path is filename
if (pos == utils::StringView<CharType>::NPos())
return std::basic_string<CharType>(path.Str(), path.Length());
return std::basic_string<CharType>(path.Str() + pos + 1, path.Length() - pos - 1);
}
template<typename CharType>
std::basic_string<CharType> Basename(const std::basic_string<CharType>& path)
{
return Basename(STRING_TO_STRINGVIEW(path));
}
template<typename CharType>
std::basic_string<CharType> DirectoryName(const utils::StringView<CharType>& path)
{
if (path.IsEmpty())
return std::basic_string<CharType>();
const size_t pos = path.RFind(IL2CPP_DIR_SEPARATOR);
if (pos == utils::StringView<CharType>::NPos())
return std::basic_string<CharType>(1, static_cast<CharType>('.'));
if (pos == 0)
return std::basic_string<CharType>(1, static_cast<CharType>('/'));
return std::basic_string<CharType>(path.Str(), pos);
}
template<typename CharType>
std::basic_string<CharType> Combine(const utils::StringView<CharType>& path1, const utils::StringView<CharType>& path2)
{
std::basic_string<CharType> result;
result.reserve(path1.Length() + path2.Length() + 1);
result.append(path1.Str(), path1.Length());
result.append(1, static_cast<CharType>(IL2CPP_DIR_SEPARATOR));
result.append(path2.Str(), path2.Length());
return result;
}
template<typename CharType>
std::basic_string<CharType> DirectoryName(const std::basic_string<CharType>& path)
{
return DirectoryName(STRING_TO_STRINGVIEW(path));
}
template<typename CharType>
std::basic_string<CharType> Combine(const std::basic_string<CharType>& path1, const std::basic_string<CharType>& path2)
{
return Combine(STRING_TO_STRINGVIEW(path1), STRING_TO_STRINGVIEW(path2));
}
template<typename CharType>
std::basic_string<CharType> Combine(const std::basic_string<CharType>& path1, const utils::StringView<CharType>& path2)
{
return Combine(STRING_TO_STRINGVIEW(path1), path2);
}
template<typename CharType>
std::basic_string<CharType> Combine(const utils::StringView<CharType>& path1, const std::basic_string<CharType>& path2)
{
return Combine(path1, STRING_TO_STRINGVIEW(path2));
}
}
} /* utils */
} /* il2cpp */

View File

@@ -0,0 +1,17 @@
#pragma once
#include <string>
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API Runtime
{
public:
static NORETURN void Abort();
static void SetDataDir(const char *path);
static std::string GetDataDir();
};
} // utils
} // il2cpp

View File

@@ -0,0 +1,272 @@
// The MIT License (MIT)
//
// Copyright(c) Unity Technologies, Microsoft Corporation
//
// 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 "il2cpp-string-types.h"
#include <string>
#include <vector>
#include <limits>
#include <stdint.h>
#include "il2cpp-config.h"
#include "StringView.h"
#include "StringViewUtils.h"
#include "Baselib.h"
namespace il2cpp
{
namespace utils
{
class LIBIL2CPP_CODEGEN_API StringUtils
{
public:
static std::string Printf(const char* format, ...);
static std::string NPrintf(const char* format, size_t max_n, ...);
static std::string Utf16ToUtf8(const Il2CppChar* utf16String);
static std::string Utf16ToUtf8(const Il2CppChar* utf16String, int maximumSize);
static std::string Utf16ToUtf8(const UTF16String& utf16String);
static UTF16String Utf8ToUtf16(const char* utf8String);
static UTF16String Utf8ToUtf16(const char* utf8String, size_t length);
static UTF16String Utf8ToUtf16(const std::string& utf8String);
static char* StringDuplicate(const char *strSource);
static Il2CppChar* StringDuplicate(const Il2CppChar* strSource, size_t length);
static bool EndsWith(const std::string& string, const std::string& suffix);
static Il2CppChar* GetChars(Il2CppString* str);
static int32_t GetLength(Il2CppString* str);
#if IL2CPP_TARGET_WINDOWS
static inline std::string NativeStringToUtf8(const Il2CppNativeString& nativeStr)
{
IL2CPP_ASSERT(nativeStr.length() < static_cast<size_t>(std::numeric_limits<int>::max()));
return Utf16ToUtf8(nativeStr.c_str(), static_cast<int>(nativeStr.length()));
}
static inline std::string NativeStringToUtf8(const Il2CppNativeChar* nativeStr)
{
return Utf16ToUtf8(nativeStr);
}
static inline std::string NativeStringToUtf8(const Il2CppNativeChar* nativeStr, uint32_t length)
{
IL2CPP_ASSERT(length < static_cast<uint32_t>(std::numeric_limits<int>::max()));
return Utf16ToUtf8(nativeStr, static_cast<int>(length));
}
static inline Il2CppNativeString Utf8ToNativeString(const std::string& str)
{
IL2CPP_ASSERT(str.length() < static_cast<size_t>(std::numeric_limits<int>::max()));
return Utf8ToUtf16(str.c_str(), str.length());
}
static inline Il2CppNativeString Utf8ToNativeString(const char* str)
{
return Utf8ToUtf16(str);
}
#else
static inline std::string NativeStringToUtf8(Il2CppNativeString& nativeStr)
{
return nativeStr;
}
static inline std::string NativeStringToUtf8(const Il2CppNativeChar* nativeStr)
{
return nativeStr;
}
static inline std::string NativeStringToUtf8(const Il2CppNativeChar* nativeStr, uint32_t length)
{
return std::string(nativeStr, length);
}
static inline Il2CppNativeString Utf8ToNativeString(const std::string& str)
{
return str;
}
static inline Il2CppNativeString Utf8ToNativeString(const char* str)
{
return str;
}
#endif
template<typename CharType, size_t N>
static inline size_t LiteralLength(const CharType(&str)[N])
{
return N - 1;
}
template<typename CharType>
static size_t StrLen(const CharType* str)
{
size_t length = 0;
while (*str)
{
str++;
length++;
}
return length;
}
template <typename CharType>
static inline bool Equals(const StringView<CharType>& left, const StringView<CharType>& right)
{
if (left.Length() != right.Length())
return false;
return memcmp(left.Str(), right.Str(), left.Length() * sizeof(CharType)) == 0;
}
template <typename CharType, size_t rightLength>
static inline bool Equals(const StringView<CharType>& left, const CharType (&right)[rightLength])
{
if (left.Length() != rightLength - 1)
return false;
return memcmp(left.Str(), right, (rightLength - 1) * sizeof(CharType)) == 0;
}
template <typename CharType>
static inline bool StartsWith(const StringView<CharType>& left, const StringView<CharType>& right)
{
if (left.Length() < right.Length())
return false;
return memcmp(left.Str(), right.Str(), right.Length() * sizeof(CharType)) == 0;
}
template <typename CharType, size_t rightLength>
static inline bool StartsWith(const StringView<CharType>& left, const CharType(&right)[rightLength])
{
if (left.Length() < rightLength - 1)
return false;
return memcmp(left.Str(), right, (rightLength - 1) * sizeof(CharType)) == 0;
}
// Taken from github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs
template<typename CharType>
static inline size_t Hash(const CharType *str, size_t length)
{
IL2CPP_ASSERT(length <= static_cast<size_t>(std::numeric_limits<int>::max()));
size_t hash1 = 5381;
size_t hash2 = hash1;
size_t i = 0;
CharType c;
const CharType* s = str;
while (true)
{
if (i++ >= length)
break;
c = s[0];
hash1 = ((hash1 << 5) + hash1) ^ c;
if (i++ >= length)
break;
c = s[1];
hash2 = ((hash2 << 5) + hash2) ^ c;
s += 2;
}
return hash1 + (hash2 * 1566083941);
}
template<typename CharType>
static inline size_t Hash(const CharType *str)
{
size_t hash1 = 5381;
size_t hash2 = hash1;
CharType c;
const CharType* s = str;
while ((c = s[0]) != 0)
{
hash1 = ((hash1 << 5) + hash1) ^ c;
c = s[1];
if (c == 0)
break;
hash2 = ((hash2 << 5) + hash2) ^ c;
s += 2;
}
return hash1 + (hash2 * 1566083941);
}
template<typename StringType>
struct StringHasher
{
typedef typename StringType::value_type CharType;
size_t operator()(const StringType& value) const
{
return Hash(value.c_str(), value.length());
}
};
template<typename CharType>
struct StringHasher<const CharType*>
{
size_t operator()(const CharType* value) const
{
return Hash(value);
}
};
#if defined(_MSC_VER)
static inline const baselib_char16_t* NativeStringToBaselib(const Il2CppNativeChar* str)
{
static_assert(sizeof(Il2CppNativeChar) == sizeof(baselib_char16_t), "type sizes should match");
return reinterpret_cast<const baselib_char16_t*>(str);
}
#else
static inline const char* NativeStringToBaselib(const Il2CppNativeChar* str)
{
static_assert(sizeof(Il2CppNativeChar) == sizeof(char), "type sizes should match");
return str;
}
#endif
};
} /* utils */
} /* il2cpp */
// Assumes str is not NULL
#if defined(_MSC_VER)
#define DECLARE_IL2CPP_STRING_AS_STRING_VIEW_OF_NATIVE_CHARS(variableName, str) \
il2cpp::utils::StringView<Il2CppNativeChar> variableName(reinterpret_cast<Il2CppString*>(str)->chars, reinterpret_cast<Il2CppString*>(str)->length);
#define DECLARE_IL2CPP_CHAR_PTR_AS_STRING_VIEW_OF_NATIVE_CHARS(variableName, str) \
il2cpp::utils::StringView<Il2CppNativeChar> variableName(str, il2cpp::utils::StringUtils::StrLen (str));
#define DECLARE_NATIVE_C_STRING_AS_STRING_VIEW_OF_IL2CPP_CHARS(variableName, str) \
il2cpp::utils::StringView<Il2CppChar> variableName(str, wcslen(str));
#define DECLARE_NATIVE_STRING_AS_STRING_VIEW_OF_IL2CPP_CHARS(variableName, str) \
il2cpp::utils::StringView<Il2CppChar> variableName = STRING_TO_STRINGVIEW(str);
#else
#define DECLARE_IL2CPP_STRING_AS_STRING_VIEW_OF_NATIVE_CHARS(variableName, str) \
Il2CppNativeString variableName##_native_string_storage = il2cpp::utils::StringUtils::Utf16ToUtf8(reinterpret_cast<Il2CppString*>(str)->chars, reinterpret_cast<Il2CppString*>(str)->length); \
il2cpp::utils::StringView<Il2CppNativeChar> variableName(variableName##_native_string_storage.c_str(), variableName##_native_string_storage.length());
#define DECLARE_IL2CPP_CHAR_PTR_AS_STRING_VIEW_OF_NATIVE_CHARS(variableName, str) \
Il2CppNativeString variableName##_native_string_storage = il2cpp::utils::StringUtils::Utf16ToUtf8(str, il2cpp::utils::StringUtils::StrLen (str)); \
il2cpp::utils::StringView<Il2CppNativeChar> variableName(variableName##_native_string_storage.c_str(), variableName##_native_string_storage.length());
#define DECLARE_NATIVE_C_STRING_AS_STRING_VIEW_OF_IL2CPP_CHARS(variableName, str) \
UTF16String variableName##_utf16String = il2cpp::utils::StringUtils::Utf8ToUtf16(str); \
il2cpp::utils::StringView<Il2CppChar> variableName = STRING_TO_STRINGVIEW(variableName##_utf16String);
#define DECLARE_NATIVE_STRING_AS_STRING_VIEW_OF_IL2CPP_CHARS DECLARE_NATIVE_C_STRING_AS_STRING_VIEW_OF_IL2CPP_CHARS
#endif

View File

@@ -0,0 +1,202 @@
#pragma once
#include "il2cpp-config.h"
#include <limits.h>
#if IL2CPP_TARGET_WINDOWS
#include <malloc.h>
#else
#include <alloca.h>
#endif
#if IL2CPP_TARGET_LINUX
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNU_PATCHLEVEL__)
#endif
namespace il2cpp
{
namespace utils
{
template<typename CharType>
class StringView
{
private:
const CharType* m_String;
size_t m_Length;
// Intended to only be used by Empty()
inline StringView() :
m_String(NULL),
m_Length(0)
{
}
public:
template<size_t Length>
inline StringView(const CharType(&str)[Length]) :
m_String(str), m_Length(Length - 1)
{
}
inline StringView(const CharType* str, size_t length) :
m_String(str), m_Length(length)
{
IL2CPP_ASSERT(str != NULL);
}
inline StringView(const CharType* str, size_t startIndex, size_t length) :
m_String(str + startIndex), m_Length(length)
{
IL2CPP_ASSERT(str != NULL);
}
inline StringView(const StringView<CharType>& str, size_t startIndex, size_t length) :
m_String(str.Str() + startIndex),
m_Length(length)
{
IL2CPP_ASSERT(startIndex + length <= str.Length());
}
// This is to work around a bug in gcc (24666) where arrays decay to pointers too fast
// This is known to be fixed by at least 7.3.0
#if IL2CPP_TARGET_LINUX && GCC_VERSION < 70300
inline StringView(const char* str) :
m_String(str), m_Length(strlen(str))
{
}
#endif
inline const CharType* Str() const
{
return m_String;
}
inline size_t Length() const
{
return m_Length;
}
inline CharType operator[](size_t index) const
{
return m_String[index];
}
inline bool IsNullTerminated() const
{
return m_String[m_Length] == 0;
}
inline bool IsEmpty() const
{
return Length() == 0;
}
static inline StringView<CharType> Empty()
{
return StringView<CharType>();
}
inline size_t Find(CharType c, size_t startIndex = 0) const
{
const CharType* end = m_String + m_Length;
for (const CharType* ptr = m_String + startIndex; ptr < end; ptr++)
{
if (*ptr == c)
return ptr - m_String;
}
return NPos();
}
inline size_t RFind(CharType c) const
{
for (const CharType* ptr = m_String + m_Length; ptr-- > m_String;)
{
if (*ptr == c)
return ptr - m_String;
}
return NPos();
}
inline StringView<CharType> SubStr(size_t startIndex, size_t length)
{
return StringView<CharType>(*this, startIndex, length);
}
inline StringView<CharType> SubStr(size_t startIndex)
{
return StringView<CharType>(*this, startIndex, Length() - startIndex);
}
inline static size_t NPos()
{
return static_cast<size_t>(-1);
}
inline bool TryParseAsInt(int& outResult)
{
if (Length() == 0)
return false;
int result = 0;
bool isNegative = false;
const CharType* ptr = m_String;
const CharType* end = m_String + m_Length;
if (ptr[0] == '-')
{
isNegative = true;
ptr++;
}
for (; ptr < end; ptr++)
{
CharType digit = *ptr;
if (digit < '0' || digit > '9')
return false;
int digitNumeric = digit - '0';
if (result > INT_MAX / 10)
return false;
result = result * 10;
if (result > INT_MAX - digitNumeric)
return false;
result += digitNumeric;
}
if (isNegative)
{
outResult = -result;
}
else
{
outResult = result;
}
return true;
}
};
#define StringViewAsNullTerminatedStringOf(CharType, stringView, variableName) \
const CharType* variableName; \
do \
{ \
if (!stringView.IsEmpty() && stringView.IsNullTerminated()) \
{ \
variableName = stringView.Str(); \
} \
else \
{ \
CharType* buffer = static_cast<CharType*>(alloca((stringView.Length() + 1) * sizeof(CharType))); \
memcpy(buffer, stringView.Str(), stringView.Length() * sizeof(CharType)); \
buffer[stringView.Length()] = 0; \
variableName = buffer; \
} \
} \
while (false)
}
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include "il2cpp-config.h"
#include <string>
#include "StringView.h"
#define STRING_TO_STRINGVIEW(sv) il2cpp::utils::StringViewUtils::StringToStringView(sv)
namespace il2cpp
{
namespace utils
{
class StringViewUtils
{
public:
template<typename CharType, typename CharTraits, typename StringAlloc>
static StringView<CharType> StringToStringView(const std::basic_string<CharType, CharTraits, StringAlloc>& str)
{
return StringView<CharType>(str.c_str(), str.length());
}
// This will prevent accidentally assigning temporary values (like function return values)
// to a string view. While this protection will only be enabled on C++11 compiles, even those
// are enough to catch the bug in our runtime
#if IL2CPP_HAS_DELETED_FUNCTIONS
template<typename CharType, typename CharTraits, typename StringAlloc>
static StringView<CharType> StringToStringView(const std::basic_string<CharType, CharTraits, StringAlloc>&& str)
{
IL2CPP_ASSERT(0 && "Cannot create stringview into R-value reference");
return StringView<CharType>::Empty();
}
#endif
};
}
}

View File

@@ -0,0 +1,46 @@
#pragma once
#include <stdint.h>
namespace il2cpp
{
namespace utils
{
namespace TemplateUtils
{
template<typename T, typename U>
struct IsSame
{
static const bool value = false;
};
template<typename T>
struct IsSame<T, T>
{
static const bool value = true;
};
template<typename B, typename D>
struct IsBaseOf
{
private:
template<typename BT, typename DT>
struct Converter
{
operator BT*() const;
operator DT*();
};
typedef int16_t Derived;
typedef int8_t NotDerived;
template<typename T>
static Derived IsDerived(D*, T);
static NotDerived IsDerived(B*, int);
public:
static const bool value = IsSame<B, D>::value || sizeof(IsDerived(Converter<B, D>(), int())) == sizeof(Derived);
};
}
}
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include "Baselib.h"
#include "Cpp/mpmc_node_queue.h"
namespace il2cpp
{
namespace utils
{
typedef baselib::mpmc_node ThreadSafeFreeListNode;
/// Lockless allocator that keeps instances of T on a free list.
///
/// T must be derived from ThreadSafeFreeListNode.
///
template<typename T>
struct ThreadSafeFreeList
{
T* Allocate()
{
T* instance = m_NodePool.try_pop_front();
if (!instance)
instance = new T();
return instance;
}
void Release(T* instance)
{
m_NodePool.push_back(instance);
}
~ThreadSafeFreeList()
{
T* instance;
while ((instance = m_NodePool.try_pop_front()) != NULL)
delete instance;
}
private:
baselib::mpmc_node_queue<T> m_NodePool;
};
} /* utils */
} /* il2cpp */

View File

@@ -0,0 +1,378 @@
#pragma once
#include "Memory.h"
#include <algorithm> // std::max
#include <memory> // std::uninitialized_fill
// dynamic_array - simplified version of std::vector<T>
//
// features:
// . always uses memcpy for copying elements. Your data structures must be simple and can't have internal pointers / rely on copy constructor.
// . EASTL like push_back(void) implementation
// Existing std STL implementations implement insertion operations by copying from an element.
// For example, resize(size() + 1) creates a throw-away temporary object.
// There is no way in existing std STL implementations to add an element to a container without implicitly or
// explicitly providing one to copy from (aside from some existing POD optimizations).
// For expensive-to-construct objects this creates a potentially serious performance problem.
// . grows X2 on reallocation
// . small code footprint
// . clear actually deallocates memory
// . resize does NOT initialize members!
//
// Changelog:
// Added pop_back()
// Added assign()
// Added clear() - frees the data, use resize(0) to clear w/o freeing
// zero allocation for empty array
//
namespace il2cpp
{
namespace utils
{
template<typename T>
struct AlignOfType
{
enum
{
align = ALIGN_OF(T)
};
};
template<typename T, size_t ALIGN = AlignOfType<T>::align>
struct dynamic_array
{
public:
enum
{
align = ALIGN
};
typedef T *iterator;
typedef const T *const_iterator;
typedef T value_type;
typedef size_t size_type;
typedef size_t difference_type;
typedef T &reference;
typedef const T &const_reference;
public:
dynamic_array() : m_data(NULL), m_size(0), m_capacity(0)
{
}
explicit dynamic_array(size_t size)
: m_size(size), m_capacity(size)
{
m_data = allocate(size);
}
dynamic_array(size_t size, T const &init_value)
: m_size(size), m_capacity(size)
{
m_data = allocate(size);
std::uninitialized_fill(m_data, m_data + size, init_value);
}
~dynamic_array()
{
if (owns_data())
m_data = deallocate(m_data);
}
dynamic_array(const dynamic_array &other) : m_size(0), m_capacity(0)
{
m_data = NULL;
assign(other.begin(), other.end());
}
dynamic_array &operator=(const dynamic_array &other)
{
// should not allocate memory unless we have to
if (&other != this)
assign(other.begin(), other.end());
return *this;
}
void clear()
{
if (owns_data())
m_data = deallocate(m_data);
m_size = 0;
m_capacity = 0;
}
void assign(const_iterator begin, const_iterator end)
{
Assert(begin <= end);
resize_uninitialized(end - begin);
memcpy(m_data, begin, m_size * sizeof(T));
}
iterator erase(iterator input_begin, iterator input_end)
{
Assert(input_begin <= input_end);
Assert(input_begin >= begin());
Assert(input_end <= end());
size_t leftOverSize = end() - input_end;
memmove(input_begin, input_end, leftOverSize * sizeof(T));
m_size -= input_end - input_begin;
return input_begin;
}
iterator erase(iterator it)
{
return erase(it, it + 1);
}
iterator erase_swap_back(iterator it)
{
m_size--;
memcpy(it, end(), sizeof(T));
return it;
}
iterator insert(iterator insert_before, const_iterator input_begin, const_iterator input_end)
{
Assert(input_begin <= input_end);
Assert(insert_before >= begin());
Assert(insert_before <= end());
// resize (make sure that insertBefore does not get invalid in the meantime because of a reallocation)
size_t insert_before_index = insert_before - begin();
size_t elements_to_be_moved = size() - insert_before_index;
resize_uninitialized((input_end - input_begin) + size(), true);
insert_before = begin() + insert_before_index;
size_t insertsize = input_end - input_begin;
// move to the end of where the inserted data will be
memmove(insert_before + insertsize, insert_before, elements_to_be_moved * sizeof(T));
// inject input data in the hole we just created
memcpy(insert_before, input_begin, insertsize * sizeof(T));
return insert_before;
}
iterator insert(iterator insertBefore, const T &t) { return insert(insertBefore, &t, &t + 1); }
void swap(dynamic_array &other) throw ()
{
std::swap(m_data, other.m_data);
std::swap(m_size, other.m_size);
std::swap(m_capacity, other.m_capacity);
}
// Returns the memory to the object.
// This does not call the constructor for the newly added element.
// You are expected to initialize all member variables of the returned data.
T &push_back()
{
if (++m_size > capacity())
reserve(std::max<size_t>(capacity() * 2, 1));
return back();
}
// push_back but it also calls the constructor for the newly added element.
T &push_back_construct()
{
if (++m_size > capacity())
reserve(std::max<size_t>(capacity() * 2, 1));
// construct
T *ptr = &back();
new(ptr) T;
return *ptr;
}
// push_back but assigns /t/ to the newly added element.
void push_back(const T &t)
{
push_back() = t;
}
void pop_back()
{
Assert(m_size >= 1);
m_size--;
}
void resize_uninitialized(size_t size, bool double_on_resize = false)
{
m_size = size;
if (m_size <= capacity())
return;
if (double_on_resize && size < capacity() * 2)
size = capacity() * 2;
reserve(size);
}
void resize_initialized(size_t size, const T &t = T(), bool double_on_resize = false)
{
if (size > capacity())
{
size_t requested_size = size;
if (double_on_resize && size < capacity() * 2)
requested_size = capacity() * 2;
reserve(requested_size);
}
if (size > m_size)
std::uninitialized_fill(m_data + m_size, m_data + size, t);
m_size = size;
}
void reserve(size_t inCapacity)
{
if (capacity() >= inCapacity)
return;
if (owns_data())
{
Assert((inCapacity & k_reference_bit) == 0 && "Dynamic array capacity overflow");
m_capacity = inCapacity;
m_data = reallocate(m_data, inCapacity);
}
else
{
T *newData = allocate(inCapacity);
memcpy(newData, m_data, m_size * sizeof(T));
// Invalidate old non-owned data, since using the data from two places is most likely a really really bad idea.
#if IL2CPP_DEBUG
memset(m_data, 0xCD, capacity() * sizeof(T));
#endif
m_capacity = inCapacity; // and clear reference bit
m_data = newData;
}
}
void assign_external(T *begin, T *end)
{
if (owns_data())
m_data = deallocate(m_data);
m_size = m_capacity = reinterpret_cast<value_type *>(end) - reinterpret_cast<value_type *>(begin);
Assert(m_size < k_reference_bit);
m_capacity |= k_reference_bit;
m_data = begin;
}
void set_owns_data(bool ownsData)
{
if (ownsData)
m_capacity &= ~k_reference_bit;
else
m_capacity |= k_reference_bit;
}
void shrink_to_fit()
{
if (owns_data())
{
m_capacity = m_size;
m_data = reallocate(m_data, m_size);
}
}
const T &back() const
{
Assert(m_size != 0);
return m_data[m_size - 1];
}
const T &front() const
{
Assert(m_size != 0);
return m_data[0];
}
T &back()
{
Assert(m_size != 0);
return m_data[m_size - 1];
}
T &front()
{
Assert(m_size != 0);
return m_data[0];
}
T *data() { return m_data; }
T const *data() const { return m_data; }
bool empty() const { return m_size == 0; }
size_t size() const { return m_size; }
size_t capacity() const { return m_capacity & ~k_reference_bit; }
T const &operator[](size_t index) const
{
Assert(index < m_size);
return m_data[index];
}
T &operator[](size_t index)
{
Assert(index < m_size);
return m_data[index];
}
T const *begin() const { return m_data; }
T *begin() { return m_data; }
T const *end() const { return m_data + m_size; }
T *end() { return m_data + m_size; }
bool owns_data() { return (m_capacity & k_reference_bit) == 0; }
bool equals(const dynamic_array &other) const
{
if (m_size != other.m_size)
return false;
for (int i = 0; i < m_size; i++)
{
if (!(m_data[i] == other.m_data[i]))
return false;
}
return true;
}
private:
static const size_t k_reference_bit = (size_t)1 << (sizeof(size_t) * 8 - 1);
T *allocate(size_t size)
{
return static_cast<T *>(IL2CPP_MALLOC_ALIGNED(size * sizeof(T), align));
}
T *deallocate(T *data)
{
Assert(owns_data());
IL2CPP_FREE_ALIGNED(data);
return NULL;
}
T *reallocate(T *data, size_t size)
{
Assert(owns_data());
return static_cast<T *>(IL2CPP_REALLOC_ALIGNED(data, size * sizeof(T), align));
}
T *m_data;
size_t m_size;
size_t m_capacity;
};
} //namespace il2cpp
} //namespace utils

View File

@@ -0,0 +1,5 @@
#pragma once
#include <stdint.h>
void sha1_get_digest(const uint8_t* buffer, int buffer_size, uint8_t digest[20]);

View File

@@ -0,0 +1,34 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "utf8/checked.h"
#include "utf8/unchecked.h"
#endif // header guard

View File

@@ -0,0 +1,327 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
#include <stdexcept>
namespace utf8
{
// Base for the exceptions that may be thrown from the library
class exception : public ::std::exception {
};
// Exceptions that may be thrown from the library functions.
class invalid_code_point : public exception {
uint32_t cp;
public:
invalid_code_point(uint32_t cp) : cp(cp) {}
virtual const char* what() const throw() { return "Invalid code point"; }
uint32_t code_point() const {return cp;}
};
class invalid_utf8 : public exception {
uint8_t u8;
public:
invalid_utf8 (uint8_t u) : u8(u) {}
virtual const char* what() const throw() { return "Invalid UTF-8"; }
uint8_t utf8_octet() const {return u8;}
};
class invalid_utf16 : public exception {
uint16_t u16;
public:
invalid_utf16 (uint16_t u) : u16(u) {}
virtual const char* what() const throw() { return "Invalid UTF-16"; }
uint16_t utf16_word() const {return u16;}
};
class not_enough_room : public exception {
public:
virtual const char* what() const throw() { return "Not enough space"; }
};
/// The library API - functions intended to be called by the users
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (!utf8::internal::is_code_point_valid(cp))
throw invalid_code_point(cp);
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
{
while (start != end) {
octet_iterator sequence_start = start;
internal::utf_error err_code = utf8::internal::validate_next(start, end);
switch (err_code) {
case internal::UTF8_OK :
for (octet_iterator it = sequence_start; it != start; ++it)
*out++ = *it;
break;
case internal::NOT_ENOUGH_ROOM:
throw not_enough_room();
case internal::INVALID_LEAD:
out = utf8::append (replacement, out);
++start;
break;
case internal::INCOMPLETE_SEQUENCE:
case internal::OVERLONG_SEQUENCE:
case internal::INVALID_CODE_POINT:
out = utf8::append (replacement, out);
++start;
// just one replacement mark for the sequence
while (start != end && utf8::internal::is_trail(*start))
++start;
break;
}
}
return out;
}
template <typename octet_iterator, typename output_iterator>
inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
return utf8::replace_invalid(start, end, out, replacement_marker);
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it, octet_iterator end)
{
uint32_t cp = 0;
internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
switch (err_code) {
case internal::UTF8_OK :
break;
case internal::NOT_ENOUGH_ROOM :
throw not_enough_room();
case internal::INVALID_LEAD :
case internal::INCOMPLETE_SEQUENCE :
case internal::OVERLONG_SEQUENCE :
throw invalid_utf8(*it);
case internal::INVALID_CODE_POINT :
throw invalid_code_point(cp);
}
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it, octet_iterator end)
{
return utf8::next(it, end);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it, octet_iterator start)
{
// can't do much if it == start
if (it == start)
throw not_enough_room();
octet_iterator end = it;
// Go back until we hit either a lead octet or start
while (utf8::internal::is_trail(*(--it)))
if (it == start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
return utf8::peek_next(it, end);
}
/// Deprecated in versions that include "prior"
template <typename octet_iterator>
uint32_t previous(octet_iterator& it, octet_iterator pass_start)
{
octet_iterator end = it;
while (utf8::internal::is_trail(*(--it)))
if (it == pass_start)
throw invalid_utf8(*it); // error - no lead byte in the sequence
octet_iterator temp = it;
return utf8::next(temp, end);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n, octet_iterator end)
{
for (distance_type i = 0; i < n; ++i)
utf8::next(it, end);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::next(first, last);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
}
else
throw invalid_utf16(static_cast<uint16_t>(cp));
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
throw invalid_utf16(static_cast<uint16_t>(cp));
result = utf8::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start != end) {
uint32_t cp = utf8::next(start, end);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start != end)
(*result++) = utf8::next(start, end);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
octet_iterator range_start;
octet_iterator range_end;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it,
const octet_iterator& range_start,
const octet_iterator& range_end) :
it(octet_it), range_start(range_start), range_end(range_end)
{
if (it < range_start || it > range_end)
throw std::out_of_range("Invalid utf-8 iterator position");
}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::next(temp, range_end);
}
bool operator == (const iterator& rhs) const
{
if (range_start != rhs.range_start || range_end != rhs.range_end)
throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
utf8::next(it, range_end);
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
utf8::next(it, range_end);
return temp;
}
iterator& operator -- ()
{
utf8::prior(it, range_start);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::prior(it, range_start);
return temp;
}
}; // class iterator
} // namespace utf8
#endif //header guard

View File

@@ -0,0 +1,329 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include <iterator>
namespace utf8
{
// The typedefs for 8-bit, 16-bit and 32-bit unsigned integers
// You may need to change them to match your system.
// These typedefs have the same names as ones from cstdint, or boost/cstdint
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Helper code - not intended to be directly called by the library users. May be changed at any time
namespace internal
{
// Unicode constants
// Leading (high) surrogates: 0xd800 - 0xdbff
// Trailing (low) surrogates: 0xdc00 - 0xdfff
const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
// Maximum valid value for a Unicode code point
const uint32_t CODE_POINT_MAX = 0x0010ffffu;
template<typename octet_type>
inline uint8_t mask8(octet_type oc)
{
return static_cast<uint8_t>(0xff & oc);
}
template<typename u16_type>
inline uint16_t mask16(u16_type oc)
{
return static_cast<uint16_t>(0xffff & oc);
}
template<typename octet_type>
inline bool is_trail(octet_type oc)
{
return ((utf8::internal::mask8(oc) >> 6) == 0x2);
}
template <typename u16>
inline bool is_lead_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
}
template <typename u16>
inline bool is_trail_surrogate(u16 cp)
{
return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u16>
inline bool is_surrogate(u16 cp)
{
return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
}
template <typename u32>
inline bool is_code_point_valid(u32 cp)
{
return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
}
template <typename octet_iterator>
inline typename std::iterator_traits<octet_iterator>::difference_type
sequence_length(octet_iterator lead_it)
{
uint8_t lead = utf8::internal::mask8(*lead_it);
if (lead < 0x80)
return 1;
else if ((lead >> 5) == 0x6)
return 2;
else if ((lead >> 4) == 0xe)
return 3;
else if ((lead >> 3) == 0x1e)
return 4;
else
return 0;
}
template <typename octet_difference_type>
inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
{
if (cp < 0x80) {
if (length != 1)
return true;
}
else if (cp < 0x800) {
if (length != 2)
return true;
}
else if (cp < 0x10000) {
if (length != 3)
return true;
}
return false;
}
enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
/// Helper for get_sequence_x
template <typename octet_iterator>
utf_error increase_safely(octet_iterator& it, octet_iterator end)
{
if (++it == end)
return NOT_ENOUGH_ROOM;
if (!utf8::internal::is_trail(*it))
return INCOMPLETE_SEQUENCE;
return UTF8_OK;
}
#define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
/// get_sequence_x functions decode utf-8 sequences of the length x
template <typename octet_iterator>
utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
template <typename octet_iterator>
utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
if (it == end)
return NOT_ENOUGH_ROOM;
code_point = utf8::internal::mask8(*it);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
code_point += (*it) & 0x3f;
return UTF8_OK;
}
#undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
template <typename octet_iterator>
utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
{
// Save the original value of it so we can go back in case of failure
// Of course, it does not make much sense with i.e. stream iterators
octet_iterator original_it = it;
uint32_t cp = 0;
// Determine the sequence length based on the lead octet
typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
const octet_difference_type length = utf8::internal::sequence_length(it);
// Get trail octets and calculate the code point
utf_error err = UTF8_OK;
switch (length) {
case 0:
return INVALID_LEAD;
case 1:
err = utf8::internal::get_sequence_1(it, end, cp);
break;
case 2:
err = utf8::internal::get_sequence_2(it, end, cp);
break;
case 3:
err = utf8::internal::get_sequence_3(it, end, cp);
break;
case 4:
err = utf8::internal::get_sequence_4(it, end, cp);
break;
}
if (err == UTF8_OK) {
// Decoding succeeded. Now, security checks...
if (utf8::internal::is_code_point_valid(cp)) {
if (!utf8::internal::is_overlong_sequence(cp, length)){
// Passed! Return here.
code_point = cp;
++it;
return UTF8_OK;
}
else
err = OVERLONG_SEQUENCE;
}
else
err = INVALID_CODE_POINT;
}
// Failure branch - restore the original value of the iterator
it = original_it;
return err;
}
template <typename octet_iterator>
inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
uint32_t ignored;
return utf8::internal::validate_next(it, end, ignored);
}
} // namespace internal
/// The library API - functions intended to be called by the users
// Byte order mark
const uint8_t bom[] = {0xef, 0xbb, 0xbf};
template <typename octet_iterator>
octet_iterator find_invalid(octet_iterator start, octet_iterator end)
{
octet_iterator result = start;
while (result != end) {
utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
if (err_code != internal::UTF8_OK)
return result;
}
return result;
}
template <typename octet_iterator>
inline bool is_valid(octet_iterator start, octet_iterator end)
{
return (utf8::find_invalid(start, end) == end);
}
template <typename octet_iterator>
inline bool starts_with_bom (octet_iterator it, octet_iterator end)
{
return (
((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
((it != end) && (utf8::internal::mask8(*it)) == bom[2])
);
}
//Deprecated in release 2.3
template <typename octet_iterator>
inline bool is_bom (octet_iterator it)
{
return (
(utf8::internal::mask8(*it++)) == bom[0] &&
(utf8::internal::mask8(*it++)) == bom[1] &&
(utf8::internal::mask8(*it)) == bom[2]
);
}
} // namespace utf8
#endif // header guard

View File

@@ -0,0 +1,241 @@
// Copyright 2006 Nemanja Trifunovic
/*
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
#include "core.h"
namespace utf8
{
namespace unchecked
{
template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result)
{
if (cp < 0x80) // one octet
*(result++) = static_cast<uint8_t>(cp);
else if (cp < 0x800) { // two octets
*(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else if (cp < 0x10000) { // three octets
*(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
else { // four octets
*(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
*(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
*(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
*(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
}
return result;
}
template <typename octet_iterator>
uint32_t next(octet_iterator& it)
{
uint32_t cp = utf8::internal::mask8(*it);
typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
switch (length) {
case 1:
break;
case 2:
it++;
cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
break;
case 3:
++it;
cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
++it;
cp += (*it) & 0x3f;
break;
case 4:
++it;
cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
++it;
cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
++it;
cp += (*it) & 0x3f;
break;
}
++it;
return cp;
}
template <typename octet_iterator>
uint32_t peek_next(octet_iterator it)
{
return utf8::unchecked::next(it);
}
template <typename octet_iterator>
uint32_t prior(octet_iterator& it)
{
while (utf8::internal::is_trail(*(--it))) ;
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
// Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
template <typename octet_iterator>
inline uint32_t previous(octet_iterator& it)
{
return utf8::unchecked::prior(it);
}
template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n)
{
for (distance_type i = 0; i < n; ++i)
utf8::unchecked::next(it);
}
template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type
distance (octet_iterator first, octet_iterator last)
{
typename std::iterator_traits<octet_iterator>::difference_type dist;
for (dist = 0; first < last; ++dist)
utf8::unchecked::next(first);
return dist;
}
template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
{
static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
while (start != end) {
uint32_t cp = utf8::internal::mask16(*start++);
// Take care of surrogate pairs first
if (utf8::internal::is_lead_surrogate(cp)) {
if (start != end) {
uint32_t trail_surrogate = utf8::internal::mask16(*start++);
if (utf8::internal::is_trail_surrogate(trail_surrogate))
cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
else
cp = replacement_marker;
}
else
cp = replacement_marker;
}
// Lone trail surrogate
else if (utf8::internal::is_trail_surrogate(cp))
cp = replacement_marker;
result = utf8::unchecked::append(cp, result);
}
return result;
}
template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
{
while (start < end) {
uint32_t cp = utf8::unchecked::next(start);
if (cp > 0xffff) { //make a surrogate pair
*result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
*result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
}
else
*result++ = static_cast<uint16_t>(cp);
}
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
{
while (start != end)
result = utf8::unchecked::append(*(start++), result);
return result;
}
template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
{
while (start < end)
(*result++) = utf8::unchecked::next(start);
return result;
}
// The iterator class
template <typename octet_iterator>
class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
octet_iterator it;
public:
iterator () {}
explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
// the default "big three" are OK
octet_iterator base () const { return it; }
uint32_t operator * () const
{
octet_iterator temp = it;
return utf8::unchecked::next(temp);
}
bool operator == (const iterator& rhs) const
{
return (it == rhs.it);
}
bool operator != (const iterator& rhs) const
{
return !(operator == (rhs));
}
iterator& operator ++ ()
{
::std::advance(it, utf8::internal::sequence_length(it));
return *this;
}
iterator operator ++ (int)
{
iterator temp = *this;
::std::advance(it, utf8::internal::sequence_length(it));
return temp;
}
iterator& operator -- ()
{
utf8::unchecked::prior(it);
return *this;
}
iterator operator -- (int)
{
iterator temp = *this;
utf8::unchecked::prior(it);
return temp;
}
}; // class iterator
} // namespace utf8::unchecked
} // namespace utf8
#endif // header guard