文章目录
(C++ 成长记录) —— 实现类似std::vector的Array类
概述
Array是平常我们在程序开发过程中经常会用到的一种数组,是一种使用非常方便的线性结构。一般只要是准备自行去写一些稍微大型一些的软件,很多时候会想着自己来封装一个类似的数组的能力,拥有一定容器能力的数组类,那么,应该思考,一个数组,应该具备怎样的能力呢?我们首先看看std对于Vector的定义:
元素是连续存储的,这意味着不仅可以通过迭代器访问元素,还可以使用指向元素的常规指针的偏移量来访问元素。这意味着指向向量元素的指针可以传递给任何需要指向数组元素的指针的函数。
那么对于咱们自己即将实现的array, 我觉得应该具备以下的一些能力:
- Array是封装动态大小数组的序列容器。
- Array能够动态的对元素进行增删查改的操作。
- Array的存储是自动处理的,可以根据需要进行扩展和收缩。
- Array通常比静态数组占用更多的空间,因为分配了更多的内存来处理未来的增长。这样,Array不需要每次插入元素时都重新分配,而只需要在额外内存耗尽时才需要重新分配。可以使用phycialLength()函数查询已分配内存的总量。
向量上常见运算的复杂度(效率)如下:
- 随机存取-常数: O ( 1 ) O(1) O(1)
- 常量中元素的插入或移除: O ( 1 ) O(1) O(1)
- 元素的插入或删除-与向量末端的距离呈线性: O ( n ) O(n) O(n)
标准库
在标准库中,有一个简单的Vector的使用的案例:
#include <iostream>
#include <vector>
int main()
{
// Create a vector containing integers
std::vector<int> v = { 7, 5, 16, 8 };
// Add two more integers to vector
v.push_back(25);
v.push_back(13);
// Print out the vector
std::cout << "v = { ";
for (int n : v) {
std::cout << n << ", ";
}
std::cout << "}; \n";
}
可见,vector是一个线性结构,能够动态的增长大小和长短,也是C++在日常开发过程中使用的最为频繁的一种容器了。
自行实现的Array类
那么,如果想要自己尝试实现,写写一个Array的类,作为基础的容器融合到自己的一些项目中,作为一个基础的组件,应该怎么写呢,尤其是对于模板的使用和理解,在这个过程中就显得尤为重要,那么下面是我个人学习过程中实现的一个Array类,仅供大家参考:
**basic_open_array.h : **
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#ifndef _BASIC_OPEN_ARRAY_H_H_
#define _BASIC_OPEN_ARRAY_H_H_
#include <memory.h>
#include <stdlib.h>
#include <algorithm>
#include <type_traits>
#include <assert.h>
#pragma pack (push, 8)
#pragma warning(disable : 4251)
typedef size_t index_t;
#define invalid_index ((index_t) - 1)
#define TZARRAY_GROWTH_THRESHOLD 0x10000
/**
* @addtogroup utility
* @{
*/
namespace Basic
{
template<class T> class ArrayMemAssignor
{
public:
static void copy(T* pDest, size_t nBufLen, const T* pSource, size_t nCount,
bool bMove, bool bSameBuffer)
{
assert((nCount <= nBufLen) && (nCount >= 0 && nCount < 0x40000000));
assert(pSource > pDest || (pDest >= pSource + nCount));
assert(bMove || !bSameBuffer);
if (nCount > 0)
{
if (bSameBuffer)
{
memmove_s(pDest, nBufLen * sizeof(T), pSource, nCount * sizeof(T));
}
else
{
memcpy_s(pDest, nBufLen * sizeof(T), pSource, nCount * sizeof(T));
}
}
}
};
template<class T> class ArrayObjectAssignor
{
public:
static void copy(T* pDest, size_t nBufLen, const T* pSource, size_t nCount,
bool bMove, bool bSameBuffer)
{
assert((nCount <= nBufLen) && (nCount >= 0 && nCount < 0x40000000));
assert(pSource > pDest || (pDest >= pSource + nCount));
assert(bMove || !bSameBuffer);
while (nCount--)
{
*pDest = *pSource;
pDest++;
pSource++;
}
}
};
template<typename T, bool>
struct ArrayElementAssignorSelector;
template<typename T>
struct ArrayElementAssignorSelector<T, false>
{
typedef ArrayObjectAssignor<T> assignor;
};
template<typename T>
struct ArrayElementAssignorSelector<T, true>
{
typedef ArrayObjectAssignor<T> assignor;
};
template<typename T>
struct ArrayElementAssignor : public ArrayElementAssignorSelector<T, std::is_pod<T>::value>::assignor
{
};
/**
* @~English
* @brief The Array class is a container of sequential elements, like std::vector.
*
* @~Chinese
* @brief Array 类是一个顺序元素的容器类,类似std::vector
*/
template <
typename T,
typename A = typename ArrayElementAssignor<T>
>
class Array
{
public:
/**
* @~English
* @brief Constructor for the Array class.
*
* @param initPhysicalLength [in] Initial physical length
* @param initGrowLength [in] Initial grow length
*
* @~Chinese
* @brief Array 类的构造函数
*
* @param initPhysicalLength [in] 初始物理长度。
* @param initGrowLength [in] 初始增长长度。
*/
Array(size_t initPhysicalLength = 0, long initGrowLength = 8);
/**
* @~English
* @brief Copy constructor for the Array class.
*
* @~Chinese
* @brief Array 类的拷贝构造函数。
*/
Array(const Array<T, A>&);
/**
* @~English
* @brief Move constructor for the Array class.
*
* @~Chinese
* @brief Array 类的移动构造函数。
*/
Array(Array<T, A>&);
/**
* @~English
* @brief Destructor for the Array class.
*
* @~Chinese
* @brief Array 类的析构函数。
*/
~Array();
/**
* @~English
* @brief Copy assignment for the Array class.
*
* @~Chinese
* @brief Array 类的复制赋值操作符。
*/
Array<T, A>& operator = (const Array<T, A>&);
/**
* @~English
* @brief Move assignment for the Array class.
*
* @~Chinese
* @brief Array 类的移动赋值操作符。
*/
Array<T, A>& operator = (Array<T, A>&);
/**
* @~English
* @brief Equal operator for the Array class.
*
* @~Chinese
* @brief Array 类的相等操作符。
*/
bool operator == (const Array<T, A>&) const;
/**
* @~English
* @brief Equal operator for the Array class.
*
* @~Chinese
* @brief Array 类的下标操作符。
*/
T& operator [] (index_t);
/**
* @~English
* @brief Equal operator for the Array class.
*
* @~Chinese
* @brief Array 类的下标操作符。
*/
const T& operator [] (index_t) const;
/**
* @~English
* @brief Get an element at the given index.
*
* @param index [in] The given index from witch the element is obtained.
* @return The obtained element.
*
* @~Chinese
* @brief 返回指定位置的元素的引用。
*
* @param index [in] 指定的索引值,从该索引值获取对应的元素.
* @return 获取到的元素.
*
*/
const T& at(index_t index) const;
/**
* @~English
* @brief Get an element at the given index.
*
* @param index [in] The given index from witch the element is obtained.
* @return The obtained element.
*
* @~Chinese
* @brief 返回指定位置的元素的引用。
*
* @param index [in] 指定的索引值,从该索引值获取对应的元素.
* @return 获取到的元素.
*
*/
T& at(index_t index);
/**
* @~English
* @brief Set a new value for an element at the given index.
*
* @param index [in] The given index from witch the element is obtained.
* @param value [in] The new value to assign.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 设置指定位置的元素的值。
*
* @param index [in] 指定的索引值,从该索引值获取对应的元素.
* @param value [in] 有待设置的新值.
* @return Array本身的引用.
*
*/
Array<T, A>& setAt(index_t index, const T& value);
/**
* @~English
* @brief Set a new value for all elements of the array.
*
* @param value [in] The new value to assign.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 设置所有位置的元素的值。
*
* @param value [in] 有待设置的新值.
* @return Array本身的引用.
*
*/
Array<T, A>& setAll(const T& value);
/**
* @~English
* @brief Return the first element of the array.
* @return The reference of first element of the array.
*
* @~Chinese
* @brief 返回第一个元素的值的引用。
*
* @return Array第一个元素的的引用.
*
*/
T& first();
/**
* @~English
* @brief Return the first element of the array.
* @return The reference of first element of the array.
*
* @~Chinese
* @brief 返回第一个元素的值的引用。
*
* @return Array第一个元素的的引用.
*
*/
const T& first() const;
/**
* @~English
* @brief Return the last element of the array.
* @return The reference of last element of the array.
*
* @~Chinese
* @brief 返回第一个元素的值的引用。
*
* @return Array最后一个元素的的引用.
*
*/
T& last();
/**
* @~English
* @brief Return the last element of the array.
* @return The reference of last element of the array.
*
* @~Chinese
* @brief 返回第一个元素的值的引用。
*
* @return Array最后一个元素的的引用.
*
*/
const T& last() const;
/**
* @~English
* @brief Append a new element at the end of the array.
*
* @param value [in] The new value to be appended.
* @return The index of the appended element.
*
* @~Chinese
* @brief 在数组末尾添加一个新的元素。
*
* @param value [in] 待增加元素的值
* @return 增加元素的最新的索引.
*
*/
size_t append(const T& value);
/**
* @~English
* @brief Append a new array at the end of the array.
*
* @param array [in] The new array to be appended.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 在数组末尾添加一个新的数组。
*
* @param value [in] 待增加元素的值
* @return 新的Array本身自身的引用。
*
*/
Array<T, A>& append(const Array<T, A>& array);
/**
* @~English
* @brief Insert a new array at the index of the array.
*
* @param index [in] The given index.
* @param value [in] The element to be inserted.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 在数组指定位置插入一个新的数组。
*
* @param index [in] 指定的索引
* @param value [in] 待插入的元素.
* @return 新的Array本身自身的引用。
*
*/
Array<T, A>& insertAt(index_t index, const T& value);
/**
* @~English
* @brief Remove an element at the given index.
*
* @param index [in] The given index.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 删除指定索引出的一个元素。
*
* @param index [in] 指定的索引
* @return 新的Array本身自身的引用。
*
*/
Array<T, A>& removeAt(index_t index);
/**
* @~English
* @brief Remove an element at the first occurrence of value searching from index start onwards.
*
* @param value [in] The value which we want to remove.
* @param start [in] The index from which we start to search.
* @return TRUE = removed, FALSE = not removed.
*
* @~Chinese
* @brief 删除首次值等于value的元素,从start索引开始向前搜索。
*
* @param value [in] 想要删除的值.
* @param start [in] 搜索的索引起始值.
* @return TRUE = 删除, FALSE = 未删除.
*
*/
bool remove(const T& value, index_t start = 0);
/**
* @~English
* @brief Remove the first element.
* @return The reference of the array.
*
* @~Chinese
* @brief 删除数组第一个元素。
*
* @return Array本身的引用.
*
*/
Array<T, A>& removeFirst();
/**
* @~English
* @brief Remove the last element.
* @return The reference of the array.
*
* @~Chinese
* @brief 删除数组最后一个元素。
*
* @return Array本身的引用.
*
*/
Array<T, A>& removeLast();
/**
* @~English
* @brief Remove all the elements in the array.
* @return The reference of the array.
*
* @~Chinese
* @brief 删除数组所有元素。
*
* @return Array本身的引用.
*
*/
Array<T, A>& removeAll();
/**
* @~English
* @brief Remove a sub sequence of the elements from the array.
* @param startIndex [in] The index from which to start remove.
* @param endIndex [in] The index from which to stop remove.
* @return The reference of the array.
*
* @~Chinese
* @brief 删除数组所有元素。
*
* @param startIndex [in] 起始删除的索引.
* @param endIndex [in] 结束删除的索引.
* @return Array本身的引用.
*
*/
Array<T, A>& removeSubArray(index_t startIndex, index_t endIndex);
/**
* @~English
* @brief Indicate whether the array contains an element equals value searching from index start.
* @param value [in] The value to search.
* @param start [in] The index from which to start search.
* @return TRUE = contained, FALSE = not contained.
*
* @~Chinese
* @brief 判断一个Array中是否存在一个值为value的元素,从start索引开始搜索。
*
* @param value [in] 待查找的值.
* @param start [in] 起始的搜索索引.
* @return TRUE = 包含, FALSE = 不包含.
*
*/
bool contains(const T& value, index_t start = 0) const;
/**
* @~English
* @brief Find an element equals value from the array.
* @param value [in] The value to search.
* @param foundAt [in] The index of the found element.
* @param start [in] The index from which to start search.
* @return TRUE = contained, FALSE = not contained.
*
* @~Chinese
* @brief 从Array中查找值为value的元素。
*
* @param value [in] 待查找的值.
* @param foundAt [in] 找到的元素的索引.
* @param start [in] 起始的搜索索引.
* @return TRUE = 包含, FALSE = 不包含.
*
*/
bool find(const T& value, index_t& index, index_t start = 0) const;
/**
* @~English
* @brief Find an element equals value from the array.
* @param value [in] The value to search.
* @return The index of the found element.
*
* @~Chinese
* @brief 从Array中查找值为value的元素。
*
* @param value [in] 待查找的值.
* @return 找到的元素的索引.
*
*/
index_t find(const T& value) const;
/**
* @~English
* @brief Find an element equals value from the array.
* @param value [in] The value to search.
* @param start [in] The index from which to start search.
* @return The index of the found element.
*
* @~Chinese
* @brief 从Array中查找值为value的元素。
*
* @param value [in] 待查找的值.
* @param start [in] 起始的搜索索引.
* @return 找到的元素的索引.
*
*/
index_t findFrom(const T& value, index_t start) const;
/**
* @~English
* @brief Return the number of elements in the array.
*
* @return The number of elements.
*
* @~Chinese
* @brief 返回Array中的元素个数。
*
* @return 元素个数.
*
*/
size_t length() const;
/**
* @~English
* @brief Check whether the array is empty.
*
* @return TRUE = empty, FALSE = not empty.
*
* @~Chinese
* @brief 检查数组是否是空的数组。
*
* @return TRUE = 空数组, FALSE = 非空数组.
*
*/
bool isEmpty() const;
/**
* @~English
* @brief Return the logical length of the array.
*
* @return The logical length.
*
* @~Chinese
* @brief 返回逻辑长度。
*
* @return 逻辑长度.
*
*/
size_t logicalLength() const;
/**
* @~English
* @brief Set the logical length of the array.
*
* @return The reference of the array itself.
*
* @~Chinese
* @brief 返回数组本身的引用。
*
* @return 数组本身的引用.
*
*/
Array<T, A>& setLogicalLength(size_t);
/**
* @~English
* @brief Return the physical length of the array.
*
* @return The physical length.
*
* @~Chinese
* @brief 返回数组的物理长度。
*
* @return 物理长度.
*
*/
size_t physicalLength() const;
/**
* @~English
* @brief Set the physical length of the array.
*
* @return The reference of the array itself.
*
* @~Chinese
* @brief 设置数组的物理长度。
*
* @return 数组本身的引用.
*
*/
Array<T, A>& setPhysicalLength(size_t);
/**
* @~English
* @brief Return the grow length of the array.
*
* @return The grow length.
*
* @~Chinese
* @brief 返回数组的增长长度。
*
* @return 增长长度.
*
*/
long growLength() const;
/**
* @~English
* @brief Set the grow length of the array.
*
* @return The reference of the array itself.
*
* @~Chinese
* @brief 设置数组的增长长度。
*
* @return 数组本身的引用.
*
*/
Array<T, A>& setGrowLength(long);
/**
* @~English
* @brief reverse the order of the array.
*
* @return The reference of the array itself.
*
* @~Chinese
* @brief 逆转数组元素的顺序。
*
* @return 数组本身的引用.
*
*/
Array<T, A>& reverse();
/**
* @~English
* @brief Exchange the two elements.
* @param i1 [in] The index of the first element to exchange.
* @param i2 [in] The index of the second element to exchange.
* @return The reference of the array itself.
*
* @~Chinese
* @brief 交换Array中的两个元素。
*
* @param i1 [in] 要交换的第一个元素的索引.
* @param i2 [in] 要交换的第二个元素的索引.
* @return Array自身的引用.
*
*/
Array<T, A>& swap(index_t i1, index_t i2);
/**
* @~English
* @brief Return the underlay dynamic allocated array.
*
* @return The pointer of the underlay array.
*
* @~Chinese
* @brief 返回Array类底下动态分配的数组。
*
* @return Array类底下数组的指针.
*
*/
const T* asArrayPtr() const;
/**
* @~English
* @brief Return the underlay dynamic allocated array.
*
* @return The pointer of the underlay array.
*
* @~Chinese
* @brief 返回Array类底下动态分配的数组。
*
* @return Array类底下数组的指针.
*
*/
T* asArrayPtr();
/**
* @~English
* @brief Return the pointer of the first element. Usual used as iterator.
*
* @return The pointer pointed to the first element.
*
* @~Chinese
* @brief 返回首元素的指针,通常作为迭代器使用。
*
* @return 指向首元素的指针.
*
*/
const T* begin() const;
/**
* @~English
* @brief Return the pointer of the first element. Usual used as iterator.
*
* @return The pointer pointed to the first element.
*
* @~Chinese
* @brief 返回首元素的指针,通常作为迭代器使用。
*
* @return 指向首元素的指针.
*
*/
T* begin();
/**
* @~English
* @brief Return the pointer of the one-beyond-last element. Usual used as iterator.
*
* @return The pointer pointed to the one-beyond-last element.
*
* @~Chinese
* @brief 返回尾元素的指针,通常作为迭代器使用。
*
* @return 指向尾元素的指针.
*
*/
const T* end() const;
/**
* @~English
* @brief Return the pointer of the one-beyond-last element. Usual used as iterator.
*
* @return The pointer pointed to the one-beyond-last element.
*
* @~Chinese
* @brief 返回尾元素的指针,通常作为迭代器使用。
*
* @return 指向尾元素的指针.
*
*/
T* end();
protected:
bool allocPhysBuf();
bool deletePhysBuf(T* pBuf, size_t nCount);
bool isValid(index_t) const;
public:
static const bool m_bSafeToMemCpy = std::is_same<A, ArrayMemAssignor<T>>::value;
T* m_pArray;
size_t m_physicalLen;
size_t m_logicalLen;
long m_growLen;
};
/** @} */
#pragma pack (pop)
// Inline implement:
template<class T, class A> inline bool
Array<T, A>::contains(const T& value, index_t start /* = 0 */) const
{
return findFrom(value, start) != -1;
}
template<typename T, typename A>
inline bool Array<T, A>::find(const T & value, index_t & index, index_t start) const
{
const index_t nFoundAt = findFrom(value, start);
if (nFoundAt == invalid_index)
{
return FALSE;
}
index = nFoundAt;
return TRUE;
}
template<typename T, typename A>
inline index_t Array<T, A>::find(const T & value) const
{
return findFrom(value, 0);
}
template<typename T, typename A>
inline index_t Array<T, A>::findFrom(const T & value, index_t start) const
{
assert(start >= 0);
if (start < 0)
{
return -1;
}
for (index_t i = start; i < (index_t)m_logicalLen; ++i)
{
if (m_pArray[i] == value)
{
return i;
}
}
return -1;
}
template<class T, class A> inline size_t
Array<T, A>::length() const
{
return m_logicalLen;
}
template<class T, class A> inline bool
Array<T, A>::isEmpty() const
{
return m_logicalLen == 0;
}
template<class T, class A> inline size_t
Array<T, A>::logicalLength() const
{
return m_logicalLen;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::setLogicalLength(size_t n)
{
assert(n >= 0);
if (n < 0)
{
n = 0;
}
assert(n < 0x40000000);
if (n > m_physicalLen)
{
const size_t growth = (m_physicalLen * sizeof(T)) < TZARRAY_GROWTH_THRESHOLD ?
m_physicalLen : TZARRAY_GROWTH_THRESHOLD / sizeof(T);
size_t minSize = m_physicalLen + std::max<size_t>(growth, m_growLen);
if (n > minSize)
{
minSize = n;
}
setPhysicalLength(minSize);
}
m_logicalLen = n;
assert(m_logicalLen <= m_physicalLen);
return *this;
}
template<class T, class A> inline size_t
Array<T, A>::physicalLength() const
{
return m_physicalLen;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::setPhysicalLength(size_t n)
{
assert(n >= 0 && n < 0x40000000);
if (n == m_physicalLen || n < 0)
{
return *this;
}
assert((m_physicalLen >= m_logicalLen) && (m_physicalLen == 0) == (m_pArray == nullptr));
T* pOldArray = m_pArray;
const size_t nOldLen = m_physicalLen;
m_physicalLen = n;
m_pArray = nullptr;
if (m_physicalLen < m_logicalLen)
{
m_logicalLen = m_physicalLen;
}
if ((m_physicalLen != 0) && allocPhysBuf())
{
A::copy(m_pArray, m_physicalLen, pOldArray, m_logicalLen, TRUE, FALSE);
}
deletePhysBuf(pOldArray, nOldLen);
return *this;
}
template<class T, class A> inline long
Array<T, A>::growLength() const
{
return m_growLen;
}
template<class T, class A> inline const T*
Array<T, A>::asArrayPtr() const
{
m_pArray;
}
template<class T, class A> inline T*
Array<T, A>::asArrayPtr()
{
return m_pArray;
}
template<class T, class A> inline const T*
Array<T, A>::begin() const
{
return m_pArray;
}
template<class T, class A> inline T*
Array<T, A>::begin()
{
return m_pArray;
}
template<class T, class A> inline const T*
Array<T, A>::end() const
{
return m_pArray + m_logicalLen;
}
template<class T, class A> inline T*
Array<T, A>::end()
{
return m_pArray + m_logicalLen;
}
template<typename T, typename A>
inline bool Array<T, A>::allocPhysBuf()
{
assert(m_physicalLen > 0);
assert(nullptr == m_pArray);
m_pArray = new T[m_physicalLen];
assert(nullptr != m_pArray);
if (nullptr == m_pArray)
{
m_physicalLen = 0;
m_logicalLen = 0;
return FALSE;
}
return TRUE;
}
template<typename T, typename A>
inline bool Array<T, A>::deletePhysBuf(T * pBuf, size_t nCount)
{
if (nullptr == pBuf)
{
assert(0 == nCount);
}
else
{
assert(nCount > 0);
delete[] pBuf;
}
return TRUE;
}
template<class T, class A> inline bool
Array<T, A>::isValid(index_t i) const
{
return i >= 0 && i < (index_t)m_logicalLen;
}
template<class T, class A> inline const T&
Array<T, A>::operator [] (index_t i) const
{
assert(isValid(i));
return m_pArray[i];
}
template<class T, class A> inline T&
Array<T, A>::operator [] (index_t i)
{
assert(isValid(i));
return m_pArray[i];
}
template<class T, class A> inline const T&
Array<T, A>::at(index_t i) const
{
assert(isValid(i));
return m_pArray[i];
}
template<class T, class A> inline T&
Array<T, A>::at(index_t i)
{
assert(isValid(i));
return m_pArray[i];
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::setAt(index_t index, const T & value)
{
assert(isValid(index));
m_pArray[index] = value;
return *this;
}
template<class T, class A> inline const T&
Array<T, A>::first() const
{
assert(!isEmpty());
return m_pArray[0];
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::setAll(const T & value)
{
for (index_t i = 0; i < m_logicalLen; ++i)
{
m_pArray[i] = value;
}
return *this;
}
template<class T, class A> inline T&
Array<T, A>::first()
{
assert(!isEmpty());
return m_pArray[0];
}
template<class T, class A> inline const T&
Array<T, A>::last() const
{
assert(!isEmpty());
return m_pArray[m_logicalLen - 1];
}
template<class T, class A> inline T&
Array<T, A>::last()
{
assert(!isEmpty());
return m_pArray[m_logicalLen - 1];
}
template<class T, class A> inline size_t
Array<T, A>::append(const T& value)
{
insertAt(m_logicalLen, value);
return m_logicalLen - 1;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::append(const Array<T, A>& array)
{
const size_t otherLen = array.length();
if (0 == otherLen)
{
return *this;
}
size_t newLen = m_logicalLen + otherLen;
if (newLen > m_physicalLen)
{
setPhysicalLength(m_logicalLen + std::max<size_t>(otherLen, m_growLen));
}
A::copy(m_pArray + m_logicalLen, (m_physicalLen - m_logicalLen), array.m_pArray, otherLen, FALSE, FALSE);
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::insertAt(index_t index, const T & value)
{
assert(index >= 0 && index <= (index_t)m_logicalLen);
if (index < 0 || index >(index_t)m_logicalLen)
{
return *this;
}
const T tmp(value);
if (m_logicalLen >= m_physicalLen)
{
assert(m_logicalLen == m_physicalLen);
size_t growth = (m_logicalLen * sizeof(T)) < TZARRAY_GROWTH_THRESHOLD ?
m_logicalLen : TZARRAY_GROWTH_THRESHOLD / sizeof(T);
setPhysicalLength(m_logicalLen + std::max<size_t>(growth, m_growLen));
}
if (index != (index_t)m_logicalLen)
{
assert(m_logicalLen >= 0);
T* p = m_pArray + m_logicalLen;
T* pStop = m_pArray + index;
do
{
*p = *(p - 1);
} while (--p != pStop);
}
m_pArray[index] = tmp;
m_logicalLen++;
return *this;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::removeAt(index_t index)
{
assert(isValid(index));
assert(m_logicalLen <= m_physicalLen);
assert(!isEmpty());
if (isEmpty() || !isValid(index))
{
return *this;
}
if (index < (index_t)m_logicalLen - 1)
{
A::copy(m_pArray + index, m_physicalLen - index, m_pArray + index + 1, m_logicalLen - 1 - index, TRUE, TRUE);
}
m_logicalLen--;
return *this;
}
template<typename T, typename A>
inline bool Array<T, A>::remove(const T & value, index_t start)
{
const index_t i = findFrom(value, start);
if (invalid_index == i)
{
return FALSE;
}
removeAt(i);
return TRUE;
}
template<class T, class A> inline Array<T, A>&
Array<T, A>::removeFirst()
{
assert(!isEmpty());
return removeAt(0);
}
template<class T, class A> inline Array<T, A>&
Array<T, A>::removeLast()
{
assert(!isEmpty());
if (!isEmpty())
{
m_logicalLen--;
}
return *this;
}
template<class T, class A> inline Array<T, A>&
Array<T, A>::removeAll()
{
setLogicalLength(0);
return *this;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::removeSubArray(index_t startIndex, index_t endIndex)
{
assert(isValid(startIndex));
assert(startIndex <= endIndex);
if (endIndex >= m_logicalLen - 1)
{
m_logicalLen = startIndex;
return *this;
}
const index_t kNumToRemove = endIndex + 1 - startIndex;
const index_t kNumToShift = m_logicalLen - 1 - endIndex;
assert(kNumToShift >= 1);
A::copy(m_pArray + startIndex, m_physicalLen - startIndex, m_pArray + endIndex + 1, kNumToShift, TRUE, TRUE);
m_logicalLen -= kNumToRemove;
return *this;
}
template<class T, class A> inline Array<T, A>&
Array<T, A>::setGrowLength(long glen)
{
assert(glen > 0);
m_growLen = glen;
return *this;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::reverse()
{
for (size_t i = 0; i < m_logicalLen / 2; ++i)
{
const T tmp = m_pArray[i];
m_pArray[i] = m_pArray[m_logicalLen - 1 - i];
m_pArray[m_logicalLen - 1 - i] = tmp;
}
return *this;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::swap(index_t i1, index_t i2)
{
assert(isValid(i1));
assert(isValid(i2));
if (i1 == i2)
{
return *this;
}
const T tmp = m_pArray[i1];
m_pArray[i1] = m_pArray[i2];
m_pArray[i2] = tmp;
return *this;
}
#define openLowMemBail() assert(FALSE)
template< class T, class A >
Array< T, A >::Array(size_t ph1, long gr1)
: m_pArray(nullptr),
m_physicalLen(ph1),
m_logicalLen(0),
m_growLen(gr1)
{
assert(m_growLen > 0);
if (m_physicalLen > 0)
{
allocPhysBuf();
}
}
template< class T, class A >
Array< T, A >::Array(const Array<T, A>& src)
: m_pArray(nullptr),
m_physicalLen(src.m_physicalLen),
m_logicalLen(src.m_logicalLen),
m_growLen(src.m_growLen)
{
assert(m_physicalLen > m_logicalLen);
if (m_logicalLen <= 0)
{
assert(0 == m_logicalLen);
m_physicalLen = 0;
}
if (m_physicalLen <= 0)
{
assert((0 == m_physicalLen) && (0 == m_logicalLen));
}
else
{
assert(m_logicalLen > 0);
if (allocPhysBuf())
{
A::copy(m_pArray, m_physicalLen, src.m_pArray, m_logicalLen, FALSE, FALSE);
}
}
}
template< class T, class A >
Array< T, A >::Array(Array<T, A>& src)
: m_pArray(nullptr),
m_physicalLen(src.m_physicalLen),
m_logicalLen(src.m_logicalLen),
m_growLen(src.m_growLen)
{
src.m_pArray = nullptr;
src.m_physicalLen = 0;
src.m_logicalLen = 0;
src.m_growLen = 8;
}
template< class T, class A >
Array< T, A >::~Array()
{
deletePhysBuf(m_pArray, m_physicalLen);
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::operator=(const Array<T, A>& src)
{
if (this != src)
{
if (src.m_logicalLen <= 0)
{
assert(0 == src.m_logicalLen);
m_logicalLen = 0;
}
else
{
if (m_physicalLen < src.m_logicalLen)
{
if (nullptr != m_pArray)
{
deletePhysBuf(m_pArray, m_physicalLen);
m_pArray = nullptr;
}
m_physicalLen = src.m_logicalLen;
if (!allocPhysBuf())
{
return *this;
}
}
m_physicalLen = src.m_logicalLen;
assert((m_logicalLen > 0) && (m_physicalLen >= m_logicalLen));
A::copy(m_pArray, m_physicalLen, src.m_pArray, m_logicalLen, FALSE, FALSE);
}
}
return *this;
}
template<typename T, typename A>
inline Array<T, A>& Array<T, A>::operator=(Array<T, A>& src)
{
if (this != src)
{
m_physicalLen = src.m_physicalLen;
m_pArray = src.m_pArray;
m_logicalLen = src.m_logicalLen;
src.m_pArray = nullptr;
src.m_physicalLen = 0;
src.m_logicalLen = 0;
src.m_growLen = 8;
}
}
template<typename T, typename A>
inline bool Array<T, A>::operator==(const Array<T, A>& cpr) const
{
if (m_logicalLen == cpr.m_logicalLen)
{
for (index_t i = 0; i < m_logicalLen; ++i)
{
if (m_pArray[i] != cpr.m_pArray[i])
{
return FALSE;
}
}
return TRUE;
}
return FALSE;
}
} // end namespace for Basic
#endif
编写简单的测试程序
当时写完了上面的代码之后,一时心血来潮,写了一个小的Qt测试的小框架,来测试一下这个类,也是试试自己有没有写错的地方,就慢慢写了一个小的框架,正好在这里做一下记录,也算是对自己的心血来潮的一个嘉奖,毕竟好记性不如烂笔头这才是硬道理。首先,可以看一下我这个测试程序运行的一个效果,对整体可以有一个印象:
然后,项目结构如下图所示:
basic_test_common_defines.h
然后,首先我来定义了一些,我自认为在测试某些类的时候,需要定义的一些通用接口,我把他放在了basic_test_common_defines.h里面,具体代码如下:
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#ifndef _BASIC_TEST_COMMON_DEFINES_H_H_
#define _BASIC_TEST_COMMON_DEFINES_H_H_
#include "zsofts_compiler_specific.h"
#include <vector>
TZ_NAMESPACE_BEGIN(TzSoftTest)
class TestCommonBase
{
public:
virtual void initProfile() { }
virtual void initData() {}
virtual void unloadProfile() {}
virtual void unloadData() {}
};
class TestCommon : public TestCommonBase
{
public:
virtual bool startAllTest() { return false; }
virtual bool startOneTest(int testId) { return false; }
virtual bool startSomeTest(int startId, int endId) { return false; }
virtual bool startSomeTest(const std::vector<int> ids) { return false; }
virtual void showTestLog() {}
};
TZ_NAMESPACE_END(TzSoftTest)
#endif // _BASIC_TEST_COMMON_DEFINES_H_H_
UI文件的设计
如上图所示,UI设计的比较简单,重点要关注一下的就是我自己提升了一个窗口的的类,进行了简单的重写,那个会在一会的文件中看到对应的代码,然后,实现这套皮肤的QSS文件在下面, 是我在一个开源的库的基础上改的,声明我给保留了:
/*
Material Dark Style Sheet for QT Applications
Author: Jaime A. Quiroga P.
Inspired on https://github.com/jxfwinter/qt-material-stylesheet
Company: GTRONICK
Last updated: 04/12/2018, 15:00.
Available at: https://github.com/GTRONICK/QSS/blob/master/MaterialDark.qss
*/
QMainWindow {
background-color:#1e1d23;
}
QDialog {
background-color:#1e1d23;
}
QColorDialog {
background-color:#1e1d23;
}
QTextEdit {
background-color:#1e1d23;
color: #a9b7c6;
}
QPlainTextEdit {
selection-background-color:#007b50;
background-color:#1e1d23;
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-width: 1px;
color: #a9b7c6;
}
QPushButton{
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-width: 1px;
border-style: solid;
color: #a9b7c6;
padding: 2px;
background-color: #1e1d23;
}
QPushButton::default{
border-style: inset;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #04b97f;
border-width: 1px;
color: #a9b7c6;
padding: 2px;
background-color: #1e1d23;
}
QToolButton {
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #04b97f;
border-bottom-width: 1px;
border-style: solid;
color: #a9b7c6;
padding: 2px;
background-color: #1e1d23;
}
QToolButton:hover{
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #37efba;
border-bottom-width: 2px;
border-style: solid;
color: #FFFFFF;
padding-bottom: 1px;
background-color: #1e1d23;
}
QPushButton:hover{
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #37efba;
border-bottom-width: 1px;
border-style: solid;
color: #FFFFFF;
padding-bottom: 2px;
background-color: #1e1d23;
}
QPushButton:pressed{
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #37efba;
border-bottom-width: 2px;
border-style: solid;
color: #37efba;
padding-bottom: 1px;
background-color: #1e1d23;
}
QPushButton:disabled{
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #808086;
border-bottom-width: 2px;
border-style: solid;
color: #808086;
padding-bottom: 1px;
background-color: #1e1d23;
}
QLineEdit {
border-width: 1px; border-radius: 4px;
border-color: rgb(58, 58, 58);
border-style: inset;
padding: 0 8px;
color: #a9b7c6;
background:#1e1d23;
selection-background-color:#007b50;
selection-color: #FFFFFF;
}
QLabel {
color: #a9b7c6;
}
QLCDNumber {
color: #37e6b4;
}
QProgressBar {
text-align: center;
color: rgb(240, 240, 240);
border-width: 1px;
border-radius: 10px;
border-color: rgb(58, 58, 58);
border-style: inset;
background-color:#1e1d23;
}
QProgressBar::chunk {
background-color: #04b97f;
border-radius: 5px;
}
QMenuBar {
background-color: #1e1d23;
}
QMenuBar::item {
color: #a9b7c6;
spacing: 3px;
padding: 1px 4px;
background: #1e1d23;
}
QMenuBar::item:selected {
background:#1e1d23;
color: #FFFFFF;
}
QMenu::item:selected {
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: #04b97f;
border-bottom-color: transparent;
border-left-width: 2px;
color: #FFFFFF;
padding-left:15px;
padding-top:4px;
padding-bottom:4px;
padding-right:7px;
background-color: #1e1d23;
}
QMenu::item {
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-bottom-width: 1px;
border-style: solid;
color: #a9b7c6;
padding-left:17px;
padding-top:4px;
padding-bottom:4px;
padding-right:7px;
background-color: #1e1d23;
}
QMenu{
background-color:#1e1d23;
}
QTabWidget {
color:rgb(0,0,0);
background-color:#1e1d23;
}
QTabWidget::pane {
border-color: rgb(77,77,77);
background-color:#1e1d23;
border-style: solid;
border-width: 1px;
border-radius: 6px;
}
QTabBar::tab {
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-bottom-width: 1px;
border-style: solid;
color: #808086;
padding: 3px;
margin-left:3px;
background-color: #1e1d23;
}
QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
border-style: solid;
border-top-color: transparent;
border-right-color: transparent;
border-left-color: transparent;
border-bottom-color: #04b97f;
border-bottom-width: 2px;
border-style: solid;
color: #FFFFFF;
padding-left: 3px;
padding-bottom: 2px;
margin-left:3px;
background-color: #1e1d23;
}
QCheckBox {
color: #a9b7c6;
padding: 2px;
}
QCheckBox:disabled {
color: #808086;
padding: 2px;
}
QCheckBox:hover {
border-radius:4px;
border-style:solid;
padding-left: 1px;
padding-right: 1px;
padding-bottom: 1px;
padding-top: 1px;
border-width:1px;
border-color: rgb(87, 97, 106);
background-color:#1e1d23;
}
QCheckBox::indicator:checked {
height: 10px;
width: 10px;
border-style:solid;
border-width: 1px;
border-color: #04b97f;
color: #a9b7c6;
background-color: #04b97f;
}
QCheckBox::indicator:unchecked {
height: 10px;
width: 10px;
border-style:solid;
border-width: 1px;
border-color: #04b97f;
color: #a9b7c6;
background-color: transparent;
}
QRadioButton {
color: #a9b7c6;
background-color: #1e1d23;
padding: 1px;
}
QRadioButton::indicator:checked {
height: 10px;
width: 10px;
border-style:solid;
border-radius:5px;
border-width: 1px;
border-color: #04b97f;
color: #a9b7c6;
background-color: #04b97f;
}
QRadioButton::indicator:!checked {
height: 10px;
width: 10px;
border-style:solid;
border-radius:5px;
border-width: 1px;
border-color: #04b97f;
color: #a9b7c6;
background-color: transparent;
}
QStatusBar {
color:#027f7f;
}
QSpinBox {
color: #a9b7c6;
background-color: #1e1d23;
}
QDoubleSpinBox {
color: #a9b7c6;
background-color: #1e1d23;
}
QTimeEdit {
color: #a9b7c6;
background-color: #1e1d23;
}
QDateTimeEdit {
color: #a9b7c6;
background-color: #1e1d23;
}
QDateEdit {
color: #a9b7c6;
background-color: #1e1d23;
}
QComboBox {
color: #a9b7c6;
background: #1e1d23;
}
QComboBox:editable {
background: #1e1d23;
color: #a9b7c6;
selection-background-color: #1e1d23;
}
QComboBox QAbstractItemView {
color: #a9b7c6;
background: #1e1d23;
selection-color: #FFFFFF;
selection-background-color: #1e1d23;
}
QComboBox:!editable:on, QComboBox::drop-down:editable:on {
color: #a9b7c6;
background: #1e1d23;
}
QFontComboBox {
color: #a9b7c6;
background-color: #1e1d23;
}
QToolBox {
color: #a9b7c6;
background-color: #1e1d23;
}
QToolBox::tab {
color: #a9b7c6;
background-color: #1e1d23;
}
QToolBox::tab:selected {
color: #FFFFFF;
background-color: #1e1d23;
}
QScrollArea {
color: #FFFFFF;
background-color: #1e1d23;
}
QSlider::groove:horizontal {
height: 5px;
background: #04b97f;
}
QSlider::groove:vertical {
width: 5px;
background: #04b97f;
}
QSlider::handle:horizontal {
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
border: 1px solid #5c5c5c;
width: 14px;
margin: -5px 0;
border-radius: 7px;
}
QSlider::handle:vertical {
background: qlineargradient(x1:1, y1:1, x2:0, y2:0, stop:0 #b4b4b4, stop:1 #8f8f8f);
border: 1px solid #5c5c5c;
height: 14px;
margin: 0 -5px;
border-radius: 7px;
}
QSlider::add-page:horizontal {
background: white;
}
QSlider::add-page:vertical {
background: white;
}
QSlider::sub-page:horizontal {
background: #04b97f;
}
QSlider::sub-page:vertical {
background: #04b97f;
}
QScrollBar:vertical {
width: 8px;
background: #DDD;
padding-bottom: 8px;
}
QScrollBar:horizontal {
height: 8px;
background: #DDD;
}
QScrollBar::handle:vertical,
QScrollBar::handle:horizontal {
background: #AAA;
}
QScrollBar::handle:vertical:hover,
QScrollBar::handle:horizontal:hover {
background: #888;
}
QScrollBar::sub-line:vertical, QScrollBar::add-line:vertical,
QScrollBar::sub-line:horizontal, QScrollBar::add-line:horizontal {
width: 2px;
height: 2px;
}
basic_array_test_tab_widget
在上面刚刚提到的一个提升的Widget的头文件代码如下:
///
// Copyright (c)2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#ifndef _BASIC_ARRAY_TEST_TAB_H_
#define _BASIC_ARRAY_TEST_TAB_H_
#include "basic_array_tests.h"
#include <QtWidgets/QWidget>
class QTextEdit;
class QProgressBar;
class TzArrayTestTab : public QWidget
{
Q_OBJECT
public:
TzArrayTestTab(QWidget* parent = nullptr);
~TzArrayTestTab();
void start();
void end();
void setEdit(QTextEdit * edit);
void setPrograssBar(QProgressBar* bar);
private:
TzSoftTest::TzArrayTests m_arrayTests;
TzSoftTest::TzOpenArrayTests m_openArrayTests;
QTextEdit* m_edit = Q_NULLPTR;
QProgressBar * m_prograssBar = Q_NULLPTR;
};
#endif
具体的实现代码如下:
///
// Copyright (c)2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#include "basic_array_test_tab_widget.h"
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QProgressBar>
TzArrayTestTab::TzArrayTestTab(QWidget* parent /* = nullptr */)
: QWidget(parent)
{
}
TzArrayTestTab::~TzArrayTestTab()
{
}
void TzArrayTestTab::start()
{
m_arrayTests.startAllTest();
m_openArrayTests.startAllTest();
}
void TzArrayTestTab::end()
{
// TODO
m_edit->clear();
}
void TzArrayTestTab::setEdit(QTextEdit * edit)
{
if (nullptr != edit)
{
m_edit = edit;
m_openArrayTests.setEdit(edit);
}
}
void TzArrayTestTab::setPrograssBar(QProgressBar * bar)
{
if (nullptr != bar)
{
m_prograssBar = bar;
m_openArrayTests.setProgressBar(bar);
}
}
basic_array_test
可以看到上述的过程中,我定义了一些test:
///
// Copyright (c)2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#include "basic_open_array.h"
#include "basic_test_common_defines.h"
#include <string>
class QProgressBar;
class QTextEdit;
TZ_NAMESPACE_BEGIN(TzSoftTest)
class ArrayTestCommon
{
public:
std::string printRetString() const { return m_printRetString; }
void setEdit(QTextEdit* edit);
void setProgressBar(QProgressBar * bar);
protected:
virtual std::string printArrays(void) { return m_printRetString; }
virtual bool commonTests() { return false; }
protected:
std::string m_printRetString;
QTextEdit* m_edit;
QProgressBar * m_prograssBar = nullptr;
};
class TzOpenArrayTests : public TestCommon, public ArrayTestCommon
{
public:
TzOpenArrayTests();
virtual ~TzOpenArrayTests();
bool startAllTest() override;
bool startOneTest(int testId) override;
bool startSomeTest(int startId, int endId) override;
bool startSomeTest(const std::vector<int> ids) override;
void showTestLog() override;
protected:
void initProfile() override;
void initData() override;
void unloadProfile() override;
void unloadData() override;
std::string printArrays(void) override;
bool commonTests() override;
private:
Basic::Array <float> m_floatArray;
Basic::Array <double> m_doubleArray;
Basic::Array <short> m_shortArray;
Basic::Array <int> m_intArray;
Basic::Array<unsigned int> m_uintArray;
Basic::Array <long> m_longArray;
};
TZ_NAMESPACE_END(TzSoftTest)
具体的实现代码如下:
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#define NOMINMAX
#include "basic_array_tests.h"
#include <random>
#include <limits>
#include <sstream>
#include <assert.h>
#include <QtWidgets/QTextEdit>
#include <QtWidgets/QProgressBar>
TZ_NAMESPACE_BEGIN(TzSoftTest)
constexpr unsigned int MaxNumOfRandomTestItems = 2000;
template<typename T>
class ArrayTestUtils
{
public:
// some generate data methods.
static void generateRealData(TzSoft::TzArray<T>& array);
static void generateRealData(Basic::Array<T>& array);
static void generateIntData(TzSoft::TzArray<T>& array);
static void generateIntData(Basic::Array<T>& array);
static bool commonInterfaceTests(const TzSoft::TzArray<T>& array);
static bool commonInterfaceTests(const Basic::Array<T>& array);
};
template<typename T>
void ArrayTestUtils<T>::generateRealData(TzSoft::TzArray<T>& array)
{
std::default_random_engine e;
for (int i = 0; i < MaxNumOfRandomTestItems; ++i)
{
std::uniform_real_distribution<T> u(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
array.append(u(e));
}
}
template<typename T>
void ArrayTestUtils<T>::generateRealData(Basic::Array<T>& array)
{
std::default_random_engine e;
for (int i = 0; i < MaxNumOfRandomTestItems; ++i)
{
std::uniform_real_distribution<T> u(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
array.append(u(e));
}
}
template<typename T>
void ArrayTestUtils<T>::generateIntData(TzSoft::TzArray<T>& array)
{
std::default_random_engine e;
for (int i = 0; i < MaxNumOfRandomTestItems; ++i)
{
std::uniform_int_distribution<T> u(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
array.append(u(e));
}
}
template<typename T>
void ArrayTestUtils<T>::generateIntData(Basic::Array<T>&array)
{
std::default_random_engine e;
for (int i = 0; i < MaxNumOfRandomTestItems; ++i)
{
std::uniform_int_distribution<T> u(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
array.append(u(e));
}
}
template<typename T>
bool ArrayTestUtils<T>::commonInterfaceTests(const TzSoft::TzArray<T>& array)
{
assert(!array.isEmpty());
assert(MaxNumOfRandomTestItems == array.length());
assert(array.at(0) == array.first());
assert(array.last() == array.at(array.length() - 1));
TzSoft::TzArray<T>tmp = array;
assert(tmp == array);
int count = 0;
for (auto it = array.begin(); it != array.end(); it++)
{
assert(nullptr != it);
assert(*it == array.at(count));
assert(*it == array[count]);
assert(array.at(count) == array[count]);
count++;
}
return true;
}
template<typename T>
bool ArrayTestUtils<T>::commonInterfaceTests(const Basic::Array<T>& array)
{
assert(!array.isEmpty());
assert(MaxNumOfRandomTestItems == array.length());
assert(array.at(0) == array.first());
assert(array.last() == array.at(array.length() - 1));
Basic::Array <T>tmp = array;
assert(tmp == array);
int count = 0;
for (auto it = array.begin(); it != array.end(); it++)
{
assert(nullptr != it);
assert(*it == array.at(count));
assert(*it == array[count]);
assert(array.at(count) == array[count]);
count++;
}
return true;
}
//
TzOpenArrayTests::TzOpenArrayTests()
{
initProfile();
initData();
}
TzOpenArrayTests::~TzOpenArrayTests()
{
unloadData();
unloadProfile();
}
bool TzOpenArrayTests::startAllTest()
{
// TODO
printArrays();
commonTests();
return false;
}
bool TzOpenArrayTests::startOneTest(int testId)
{
// TODO
printArrays();
return false;
}
bool TzOpenArrayTests::startSomeTest(int startId, int endId)
{
// TODO
printArrays();
return false;
}
bool TzOpenArrayTests::startSomeTest(const std::vector<int> ids)
{
// TODO
printArrays();
return false;
}
void TzOpenArrayTests::showTestLog()
{
// TODO
}
void TzOpenArrayTests::initProfile()
{
// TODO
}
void TzOpenArrayTests::initData()
{
ArrayTestUtils<float>::generateRealData(m_floatArray);
ArrayTestUtils<double>::generateRealData(m_doubleArray);
ArrayTestUtils<unsigned int>::generateIntData(m_uintArray);
ArrayTestUtils<int>::generateIntData(m_intArray);
ArrayTestUtils<short>::generateIntData(m_shortArray);
ArrayTestUtils<long>::generateIntData(m_longArray);
}
void TzOpenArrayTests::unloadProfile()
{
// TODO
}
void TzOpenArrayTests::unloadData()
{
// TODO
}
std::string TzOpenArrayTests::printArrays(void)
{
// m_printRetString.clear();
m_prograssBar->setValue(0);
// m_printRetString.append("This is a float random array's output: \n");
m_edit->append(QStringLiteral("This is a float random array's output:"));
// std::ostringstream buffer;
QString str;
// deal with the float array.
for (decltype(m_floatArray.length()) i = 0; i < m_floatArray.length(); ++i)
{
str += QString::number(m_floatArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 1);
// deal with the double array.
m_edit->append(QStringLiteral("This is a double random array's output:"));
for (decltype(m_doubleArray.length()) i = 0; i < m_doubleArray.length(); ++i)
{
str += QString::number(m_doubleArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 2);
// deal with the int array.
m_edit->append(QStringLiteral("This is a int random array's output:"));
for (decltype(m_intArray.length()) i = 0; i < m_intArray.length(); ++i)
{
str += QString::number(m_intArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 3);
// deal with the short array.
m_edit->append(QStringLiteral("This is a short random array's output:"));
for (decltype(m_shortArray.length()) i = 0; i < m_shortArray.length(); ++i)
{
str += QString::number(m_shortArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 4);
// deal with the uint array.
m_edit->append(QStringLiteral("This is a uint random array's output:"));
for (decltype(m_uintArray.length()) i = 0; i < m_uintArray.length(); ++i)
{
str += QString::number(m_uintArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 5);
// deal with the long array.
m_edit->append(QStringLiteral("This is a long random array's output:"));
for (decltype(m_longArray.length()) i = 0; i < m_longArray.length(); ++i)
{
str += QString::number(m_longArray.at(i)) + '\t';
// buffer << m_floatArray.at(i) << '\t';
if (i % 8 == 0)
{
// buffer << '\n';
m_edit->append(str);
str.clear();
}
}
// m_printRetString.append(buffer.str());
// m_printRetString.append("\n");
// buffer.clear();
m_prograssBar->setValue(100 / 6 * 6);
m_prograssBar->setValue(100);
return m_printRetString;
}
bool TzOpenArrayTests::commonTests()
{
ArrayTestUtils<float>::commonInterfaceTests(m_floatArray);
ArrayTestUtils<double>::commonInterfaceTests(m_doubleArray);
ArrayTestUtils<unsigned int>::commonInterfaceTests(m_uintArray);
ArrayTestUtils<int>::commonInterfaceTests(m_intArray);
ArrayTestUtils<short>::commonInterfaceTests(m_shortArray);
ArrayTestUtils<long>::commonInterfaceTests(m_longArray);
return true;
}
//
void ArrayTestCommon::setEdit(QTextEdit * edit)
{
if (nullptr != edit)
{
m_edit = edit;
}
}
void ArrayTestCommon::setProgressBar(QProgressBar * bar)
{
if (nullptr != bar )
{
m_prograssBar = bar;
}
}
TZ_NAMESPACE_END(TzSoftTest)
basic_test
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#ifndef _BASIC_TESTS_H_
#define _BASIC_TESTS_H_
#include <QtWidgets/QMainWindow>
#include "ui_BasicTests.h"
class BasicTests : public QMainWindow
{
Q_OBJECT
public:
BasicTests(QWidget *parent = Q_NULLPTR);
public slots:
void on_Array_start_pushButton_clicked(bool checked);
void on_Array_end_pushButton_clicked(bool checked);
private:
Ui::BasicTestsClass ui;
};
#endif // _BASIC_TESTS_H_
///
// Copyright (c) 2021, Tom Zhao personal. ("TZOpenTools")
// This software is a personal tools project by Tom Zhao.
// Description:
///
#include "BasicTests.h"
#include <QtWidgets/QMessageBox>
BasicTests::BasicTests(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.ArrayTestTab->setEdit(ui.Array_textEdit);
ui.ArrayTestTab->setPrograssBar(ui.ArrayTestProgressBar);
}
void BasicTests::on_Array_start_pushButton_clicked(bool checked)
{
QMessageBox::information(this, QStringLiteral("开始测试"), QStringLiteral("这是一个针对Array和TzArray的简单测试"), QMessageBox::Yes);
ui.ArrayTestTab->start();
}
void BasicTests::on_Array_end_pushButton_clicked(bool checked)
{
QMessageBox::information(this, QStringLiteral("结束测试"), QStringLiteral("这是一个针对Array和TzArray的简单测试"), QMessageBox::Yes);
ui.ArrayTestTab->end();
}
main
#include "BasicTests.h"
#include <QtWidgets/QApplication>
#include <QtCore/QFile>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFile qss(":/style/res/MaterialDark.qss");
if (qss.open(QFile::ReadOnly))
{
qDebug("open success");
QString style = QLatin1String(qss.readAll());
a.setStyleSheet(style);
qss.close();
}
else
{
qDebug("Open failed");
}
BasicTests w;
w.show();
return a.exec();
}
个人格言
用心去感受你自己需要坚持的生活,未来慢慢会给你答案的。