C language implementation of a generic vector

Problem Description:

$ C $ using plain language to implement a generic $ vector $, supports the copy constructor and mobile configurations.

Design:

$ Vector $ is dynamic arrays, so we save the pointer memory block $ vector $ apply, in addition we take two $ size $ _ $ t $ the type of save space opened up by the current number of elements and the present have been there . It needs a $ vector $ structures we define the following:

struct vector
{
	T* buf;
	size_t size, capacity;
};

 Because we design is generic $ vector $, $ T $ type variable, so an element of occupied memory variable, so the size of the memory block can not be considered two options:

1. $ $ $ increase in a structure Vector $ $ element $ _ $ size $, $ create an incoming Vector $ element when the size of the memory block and then the application time can be calculated automatically.

2. Use $ $ $ void * $ point directly to the element, so that the child need not completely consider the size of the element, because the size of the pointer is fixed.

The first embodiment is simple, but if need to copy the entire $ $ Vector, and the element is a structure and it contains a pointer (bottom left), there will be two $ $ Vector element pointing to the same location in the same data block (lower right).

Copy ago:

After copying:

If you modify the $ dat $ $ vector $ in another, and then another $ dat $ accessed in another $ vector $ may be wrong. Meanwhile, when such data push_back $ $, manually copying or transmission parameters, too much trouble. At the same time when the destructor is relatively cumbersome, requiring manual transmission parameters. Saved copy constructor and destructor in each structural body such that a lot of space will be wasted.

Improvement: Save copy constructor and destructor group element in the $ $ Vector structured body, and then use this solution.

Great! You find a Chinese point of blind students. You will be surprised by the move like this can not be achieved constructed.

The second scheme uses $ void * $, and then point to this data element. However, this way has a pointer to the structure, there are still such problems, we refer to a development of the idea of ​​the above, plus the element space, copy constructor and destructor this problem is solved, and the time for mobile configuration directly assigned to the data element pointer Vector $ $ a certain location.

Snapped! It looks perfect.

Then we began to realize it:

First copy constructor and destructor bulk data elements into more than $ vector $ ugly, we package it (take the name of my mess) :

struct data_arg
{
	size_t u_size;
	void* (*assign)(const void* _src);
	void* (*destroy)(void* _dat);
};

 Then we design a $ vector $ structures in accordance with Option II above:

struct vector
{
	void** buf;
	size_t size, capacity;
	data_arg dat_arg;
};

 Then we began to design the function:

(Note: $ catch $ _ $ exec $ is a library exception handling my project, Tell me what ignores its own just fine)

The first is to create:

* vec_init vector (data_arg _dat_arg)
{
	vector* ptr = (vector*)malloc(sizeof(vector));
	*ptr = { (void**)malloc(sizeof(void*) * vec_init_size),
		0,vec_init_size,_dat_arg 
	};
	return ptr;
}

Relatively simple, do not say.

Then implementing a function copy constructor and destructor call data:

void* vec_new_data(vector* _vec, const void* _dat)
{
	if (!_vec->dat_arg.assign)
	{
		void* dst = malloc(_vec->dat_arg.u_size);
		memcpy (dst, _dat, _vec-> dat_arg.u_size);
		return dst;
	}
	return _vec-> dat_arg.assign (_DAT);
}
void * vec_delete_data (_vec vector *, void * _date)
{
	if (!_vec->dat_arg.destroy)
		free (_dat);
	else
		_vec-> dat_arg.destroy (_dat);
	return NULL;
}

 Note: I have designed the structure if it is free of pointers directly copy the memory, so that the sub-copy constructor and destructor pointers are NULL $ $, a little higher efficiency.

Then the copy constructor:

void* vec_assign(const void* _vec)
{
	if (!_vec)
		catch_exce(6);
	* Case vector = (Vector *) _ case;
	newvec vector * = vec_init (erudite> dat_arg);
	vec_resize(newvec, vec->capacity);
	newvec->size = vec->size;
	for (int i = 0; i < newvec->size; ++i)
		newvec->buf[i] = vec->dat_arg.assign(vec->buf[i]);
	return newvec;
}

 And then empty the destructor duo:

void vec_clear(vector* _vec)
{
	if (!_vec)
		catch_exce(6);
	for (int i = 0; i < _vec->size; ++i)
		_vec-> buf [i] = vec_delete_data (_Vec, _vec-> buf [i]);
}
void* vec_destroy(void* _vec)
{
	if (!_vec)
		catch_exce(6);
	* Case vector = (Vector *) _ case;
	vec_clear (case);
	free(vec->buf);
	free (thing);
	return NULL;
}

 Then the rest of the functions themselves realize what gets the job done.

Check the capacity:

void vec_check_capacity(vector* _vec)
{
	if (!_vec)
		catch_exce(6);
	if (_vec->size == _vec->capacity)
		vec_resize(_vec, _vec->capacity << 1);
}

 

Resize:

size_t vec_resize(vector* _vec, size_t _size)
{
	if (!_vec)
		catch_exce(6);
	void** tmp = (void**)realloc(_vec->buf, sizeof(void*) * _size);
	if (!tmp)
		catch_exce(6);
	_vec->buf = tmp, _vec->capacity = _size;
	return _vec->capacity;
}

 $ Push $ _ $ back $ (copy), $ push $ _ $ back $ _ $ no $ _ $ copy $ (movement)

size_t vec_push_back(vector* _vec, void* _dat)
{
	if (!_vec)
		catch_exce(6);
	if (!_dat)
		catch_exce(7);
	vec_check_capacity (_Vec);
	_vec->buf[_vec->size++] = vec_new_data(_vec, _dat);
	return _vec->size;
}
size_t vec_push_back_no_copy(vector* _vec, void* _dat)
{
	if (!_vec)
		catch_exce(6);
	if (!_dat)
		catch_exce(7);
	vec_check_capacity (_Vec);
	_vec->buf[_vec->size++] = _dat;
	return _vec->size;
}

 $ Pop $ _ $ back $ (destructor), $ pop $ _ $ back $ _ $ no $ _ $ delete $ (not destructor)

size_t vec_pop_back(vector* _vec)
{
	if (!_vec)
		catch_exce(6);
	_vec->buf[--_vec->size] = vec_delete_data(_vec, _vec->buf[_vec->size]);
	return _vec->size;
}
size_t vec_pop_back_no_delete(vector* _vec)
{
	if (!_vec)
		catch_exce(6);
	_vec->buf[--_vec->size] = NULL;
	return _vec->size;
}

 Note: There is no border checks, Tell me add their own.

Thank you everyone!

All source code to see here . This is a $ C parser and lexical items $ subset of the language of my own pure language of $ C $, which requires the use of generic $ vector $, so the design.

Guess you like

Origin www.cnblogs.com/Aya-Uchida/p/12556365.html