Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 2 [3] 4 5   Вниз
  Печать  
Автор Тема: Подскажите с STL  (Прочитано 41858 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #60 : 03-08-2010 05:05 » 

ой, я и забыл. Вот, что получилось, будучи заточенное для моих нужд и специфику применения ))
Только вряд ли кому-то это пригодится.
Код:
#pragma once

#include <vector>

//CSimpleTypesFIFO стек FIFO для простых типов.
//Под простыми понимаются типы, которые можно безболезненно
//копировать побайтово (например, функцией memmove)
//
//Работает следующим образом: пока возможно, добавляет элементы в конец буфера.
//Если достигнут конец буфера, то делается попытка сдвинуть все данные в начало
//буфера (ведь там могут быть уже извлечённые элементы) и новые данные пишутся
//снова в конец. Если стек переполнен, то ничего не делается
//Таким образом, массив элементов всегда линейный и сплошной
template<typename ASimpleType>
class CSimpleTypesFIFO
{
std::vector<ASimpleType> m_buff;
DWORD m_BegIndx;
DWORD m_EndIndx;//всегда m_EndIndx>=m_BegIndx

public:

CSimpleTypesFIFO(DWORD dwdMaxLen=0)
{
m_BegIndx=0;
m_EndIndx=0;
m_buff.resize(dwdMaxLen);
}

void Clear()
{
m_BegIndx=0;
m_EndIndx=0;
}

//вернёт true, если было сжато пустое место
bool DeleteEmptySpace()
{
if(!m_buff.size())return false;
if(!m_BegIndx)return false;//нечего сжимать

if(m_BegIndx==m_EndIndx)
{
//стек полностью пуст
m_BegIndx=0;
m_EndIndx=0;
}
else
{
DWORD count=GetDataSize();
//сдвигаем всё к началу вектора
memmove(&m_buff[0],&m_buff[m_BegIndx],count*sizeof(m_buff[0]));
//корректируем индексы
m_BegIndx=0;
m_EndIndx=m_BegIndx+count;
}

return true;
}

//возвращает, сколько элементов можно положить в стек
DWORD GetCommonEmptySize() const
{
if(!m_buff.size())return 0;
ASSERT(m_buff.size()>=GetDataSize());
return m_buff.size() -GetDataSize();
}

//возвращает полный размер всего буфера
DWORD GetCommonBufferSize() const
{
return m_buff.size();
}

void Resize(DWORD dwdMaxLen)
{
if(m_buff.size()==dwdMaxLen)return;

//сдвигаем всё к началу
DeleteEmptySpace();
if(!dwdMaxLen)
{
m_buff.resize(0);
m_BegIndx=0;
m_EndIndx=0;
return;
}

//запоминаем предыдущее количество элементов в стеке
DWORD count=GetDataSize();

if(count>dwdMaxLen)
{
//удалить самые первые элементы
DWORD dwdToDel=(count-dwdMaxLen);
//новое количество
count=dwdMaxLen;

ASSERT(dwdToDel>0);
ASSERT(count>0);

//сдвигаем всё к началу вектора
memmove(&m_buff[0],&m_buff[dwdToDel-1],count*sizeof(m_buff[0]));
//корректируем индексы
m_BegIndx=0;
m_EndIndx=m_BegIndx+count;
}

//меняем размер стека
m_buff.resize(dwdMaxLen,0);

count=min(count,m_buff.size());

m_BegIndx=0;
m_EndIndx=m_BegIndx+count;
}

//возвращает длину пустого хвоста
DWORD GetTailSize() const
{
if(!m_buff.size())return 0;
//if(!GetDataSize())return 0;
ASSERT(m_buff.size()>=m_EndIndx);
return m_buff.size() -m_EndIndx;
}

ASimpleType* GetTailBeg() const
{
if(!m_buff.size())return 0;

if(m_BegIndx>=m_buff.size())
{
ASSERT(m_BegIndx==m_EndIndx);
ASSERT(m_BegIndx==m_buff.size());
return 0;
}

if(m_EndIndx==m_buff.size())return 0;
ASSERT(m_EndIndx<m_buff.size());
(ASimpleType*)return &m_buff[m_EndIndx];
}

DWORD GetDataSize() const
{
ASSERT(m_EndIndx>=m_BegIndx);
return m_EndIndx -m_BegIndx;
//0 1 2 3 4 5 6 7 8 9| 10
//. . . * * * * . . .|
//      B       E    |
//
//7-3 == 4
}

ASimpleType* GetDataBeg() const
{
if(!m_buff.size())return 0;
if(m_BegIndx>=m_buff.size())
{
ASSERT(m_BegIndx==m_EndIndx);
ASSERT(m_BegIndx==m_buff.size());
return 0;
}

return (ASimpleType*)&m_buff[m_BegIndx];
}

//сказать классу, что в хвост вручную записали элементы
//(количество - не более GetTailSize() - на совести программиста,
//ведь счётчик то не сдвинется дальше, но память будет уже испорчена
//извне)
DWORD ImitatePush(DWORD dwdCount)
{
ASSERT(dwdCount<=GetTailSize());
DWORD dwdToSave=min(dwdCount,GetTailSize());
m_EndIndx+=dwdToSave;
ASSERT(m_EndIndx<=m_buff.size());
return dwdToSave;
}

//сказать классу, что из начала вручную извлечены элементы
//(количество - не более GetDataSize() )
void ImitatePop(DWORD dwdCount)
{
ASSERT(m_BegIndx<m_buff.size());
m_BegIndx+=min(dwdCount,GetDataSize());
ASSERT(m_BegIndx<=m_EndIndx);

ASSERT(m_BegIndx<=m_buff.size());
ASSERT(m_EndIndx<=m_buff.size());

if(m_BegIndx==m_EndIndx)
{
m_BegIndx=0;
m_EndIndx=0;
}
}
};

« Последнее редактирование: 03-08-2010 08:43 от Алексей1153++ » Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #61 : 03-08-2010 06:59 » 

То есть, он у тебя не кольцевой, ты его просто расширяешь для дозаписи?
Я бы, наверное, сделал по образцу stl - сделал бы вставку в него push(IterType first, IterType last), а доступ к памяти не открывал бы. Правда, там ещё извлечение данных из головы сразу куском...
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #62 : 03-08-2010 07:05 » 

Вад, нет, я не расширяю, размер буфера постоянный. Аналогия с кольцом в том, что begin и end (m_BegIndx и m_EndIndx) "ползут" по буферу в старшие адреса - при добавлении данных сдвигается end, при выборке - begin. То есть в начале буфера начинает образовываться "пустота". Как только end сдвинуть некуда, пустота уничтожается сдвигом данные в начало буфера, а новые данные начинают записываться в освободившуюся конечную часть.

Если весь буфер оказался забит, а сообщение по протоколу так и не выделено, значит сообщение слишком велико для буфера - буфер просто очищу.
(последнее предложение - это внешняя логика, а не класса)

Данные принимаются произвольными кусками, а потом только анализируются на протокол. Отсюда такая открытость памяти класса - для простоты

Чего добивался:
1) отсутствие переаллокации
2) терпимо редкий вызов memmove (сообщения много короче буфера)
3) запись в буфер кусками, и чтение тоже кусками
4) массив с данными непрерывен
« Последнее редактирование: 03-08-2010 07:54 от Алексей1153++ » Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #63 : 03-08-2010 07:26 » 

Теперь понятно, почему так Улыбаюсь
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #64 : 03-08-2010 07:46 » 

Цитата: Алексей1153++
Как только end сдвинуть некуда, пустота уничтожается сдвигом данные в начало буфера, а новые данные начинают записываться в освободившуюся конечную часть.
По-моему это лишнее действие. Достаточно end перенести в начало. При этом лишь несколько усложнится определение количества занятых и свободных, а всё остальное останется более-менее без изменений.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #65 : 03-08-2010 07:53 » 

Dimka, не, не пойдёт: для пользователя класса массив непрерывен

(4-й пункт добавил теперь )) )
Записан

lapulya
Молодой специалист

ru
Offline Offline

« Ответ #66 : 03-08-2010 11:53 » 

Я бы сделал так, как предложил Димка в последнем посте, а твой 4 пункт обеспечился бы твоей же функцией сдвига всего в начало ТОЛЬКО при запросе самого массива (т.е. при вставке/выборке мы ничего никуда не двигаем, а именно смещаем по кольцу, но при этом end может быть меньше begin). так будет быстрее работать.
Записан

С уважением Lapulya
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #67 : 03-08-2010 13:41 » 

какой смыл иметь непрерывный блок элементов?
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #68 : 03-08-2010 14:08 » 

Так пришлось бы сначала копировать часть массива, а только потом разбирать. Другие составляющие программы не умеют с кольцом работать, им подавай буфер и длину буфера
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #69 : 04-08-2010 07:32 » 

я полагал, что обычно сообщения обрабатываются по одному
почему внешняя хреновина должны пытаться выдрать их пачкой?

Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #70 : 04-08-2010 07:36 » 

почему пачкой?

Ситуация такая: в кольце лежит неразобранный протокол. Чтобы обработать сообщение, нужно взять буфер с данными и подсунуть на обработку. Из данных выделяется одно сообщение и отдаётся на обработку дальше, а из кольца удаляется.

Если ситуация будет такой, что начало данный в конце буфера, а конец - в начале (как может быть в кольце), то функция разбора это не поймёт - ей нужен непрерывный участок памяти

Отдал сегодня тестировать программу в полевых условиях ))

Добавлено через 1 минуту и 23 секунды:
Антон (LogRus), я, кажется, понял, что тебя смущает. Дело в том, что у меня ASimpleType==BYTE , а не <некая структура>
« Последнее редактирование: 04-08-2010 07:38 от Алексей1153 » Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #71 : 04-08-2010 07:39 » 

тогда понятно, просто я бы наверное резал был на сообщения при входе в очередь
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #72 : 04-08-2010 07:49 » 

тогда понятно, просто я бы наверное резал бы на сообщения при входе в очередь
представь - с ком-порта идут данные, причём произвольными кусками (но в правильной очерёдности). Чтобы не терять время на таймаутах, я смотрю, сколько байтов лежит в буфере кома и сразу считываю все или меньше (таким образом таймауты не возникают, так как это количестко точно прочитается прямо сейчас).
Это всё читается в тот самый буфер.
Конечно, можно и разрезАть сразу, но это дополнительный контейнер, а если без дополнительного - то проще сразу из буфера доставать, никуда промежуточно не копируя. Что и сделал )

Или ты как имел в виду сделать ?
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #73 : 10-08-2010 06:50 » 

ну у тебя и так получилось промежуточное хранилище
наверное у меня черезмерное стремление всё усложнять Улыбаюсь
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #74 : 10-08-2010 07:22 » 

Написал, кстати, только что аналогичный (но реально кольцевой) буфер для элементов-контейнеров (щас тестировать сажусь )) )
Подойдёт, в принципе, для любых типов, не только контейнеров
Код:
template<typename ASTLType>
class CSTLTypesRING
{
CCriticalSection m_cris;
struct s_ptr
{
ASTLType* m_p;

s_ptr()
{
m_p=0;
}

void createIfNotYet()
{
if(!m_p)
{
m_p=new ASTLType;
}
}

~s_ptr()
{
if(m_p)
{
delete m_p;
m_p=0;
}
}

void operator=(const s_ptr& o2)
{
ASTLType* p=o2.m_p;
((s_ptr&)o2).m_p=0;
m_p=p;
}
};

typedef std::vector<s_ptr> td_buff;
td_buff m_buff;
DWORD m_BegIndx;//указывает на 1-й элемент
DWORD m_EndIndx;//указывает на следующий за последним (поэтому размер буфера +1 - всегда один пустой элемент)
//если пусто, то m_BegIndx==m_EndIndx

bool m_bUseThreadSyncronizing;

public:

CSTLTypesRING(bool bUseThreadSyncronizing,DWORD dwdMaxLen=0)
{
m_bUseThreadSyncronizing=bUseThreadSyncronizing;
DWORD dwdRealSize=dwdMaxLen+1;
m_BegIndx=0;
m_EndIndx=0;
m_buff.resize(dwdRealSize);
}

//если размер меняется, всё предыдущие значения очищаются
//если остаётся такой же - ничего не происходит
void Resize(DWORD dwdMaxLen)
{
CSingleLock SL(&m_cris,m_bUseThreadSyncronizing?1:0);

DWORD dwdRealSize=dwdMaxLen+1;
if(m_buff.size()==dwdRealSize)return;

m_buff.clear();
m_buff.resize(dwdRealSize);
m_BegIndx=0;
m_EndIndx=0;
}

ASTLType* TestCanPush()
{
CSingleLock SL(&m_cris,m_bUseThreadSyncronizing?1:0);
if(!IncrementEnd(true))return 0;
m_buff[m_EndIndx].createIfNotYet();
return m_buff[m_EndIndx].m_p;
}

//возвращает указатель на контейнер, который можно заполнять
//если нет места - вернёт 0
void Imitate_Push()
{
CSingleLock SL(&m_cris,m_bUseThreadSyncronizing?1:0);
IncrementEnd();
}

ASTLType* TestCanPop()
{
CSingleLock SL(&m_cris,m_bUseThreadSyncronizing?1:0);
if(!IncrementBeg(true))return 0;
return m_buff[m_BegIndx].m_p;
}

void Imitate_Pop()
{
CSingleLock SL(&m_cris,m_bUseThreadSyncronizing?1:0);
IncrementBeg();
}

private:
bool IncrementEnd(bool bJustTest=false)
{
if(m_buff.size()<1)return false;
ASSERT(m_EndIndx<m_buff.size());
ASSERT(m_BegIndx<m_buff.size());

if(m_BegIndx<=m_EndIndx)
{
//..*****+..|
//..b....e..|
//или
//....+.....|
//....b.....|
//....e.....|

if(m_EndIndx+1==m_buff.size())
{
//..*******+|
//..b......e|
//или
//.........+|
//.........b|
//.........e|

if(m_BegIndx==0)
{
//*********+|
//b........e|
//или
//----------|
//----------|
//----------|
return false;

}
else
{
//..*******+|
//..b......e|
//или
//.........+|
//.........b|
//.........e|
if(!bJustTest)m_EndIndx=0;
return true;
}
}
else
{
//..*****+..|
//..b....e..|
//или
//....+.....|
//....b.....|
//....e.....|
if(!bJustTest)m_EndIndx++;
return true;
}
}
else
{
//**+....***|
//..e....b..|

if(m_EndIndx+1==m_BegIndx)
{
//******+***|
//......eb..|
return false;
}
else
{
//**+....***|
//..e....b..|
if(!bJustTest)m_EndIndx++;
return true;
}
}

return false;//сюда не попадём
}

bool IncrementBeg(bool bJustTest=false)
{
if(m_buff.size()<1)return false;
ASSERT(m_EndIndx<m_buff.size());
ASSERT(m_BegIndx<m_buff.size());

if(m_BegIndx==m_EndIndx)
{
//....+.....|
//....b.....|
//....e.....|
return false;
}

if(!bJustTest)
{
if(m_BegIndx<m_EndIndx)
{
//..*****+..|
//..b....e..|

m_BegIndx++;
}
else
{
//**+....***|
//..e....b..|

if(m_BegIndx+1==m_buff.size())
{
m_BegIndx=0;
}
else
{
//**+....***|
//..e....b..|
m_BegIndx++;
}
}
}


return true;

}
};


вроде работает )

возможность использования при многопоточности также учтена - можно выбрать в конструкторе

Добавлено через 22 дня, 4 часа, 11 минут и 26 секунд:
любопытный спецэффект
Код:
std::string s;
s.resize(5,0);//теперь строка считает, что состоит из 5 нулей

std::string s2;

s2="111"+s2+"222"; // по сути, получается "111\0\0\0\0\0222"
//в итоге s2=="111"

эхъ. Час парился, пока допёрло

А применил resuze случайно при работе с mysql_real_escape_string
« Последнее редактирование: 02-09-2010 10:09 от Алексей1153 » Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #75 : 02-09-2010 11:07 » 

и правильно считает, очень правильное поведение
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #76 : 02-09-2010 11:22 » 

С точки зрения контейнера - да, но с точки зрения строки - лажа полная.
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #77 : 03-09-2010 03:13 » 

по моему и так и так правильно, всё таки string и Null Terminated String это разные вещи
Кстати, стринг отлично заменяет vector<char> сам много раз им пользовался при передаче данных по сети Улыбаюсь
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #78 : 03-09-2010 05:07 » 

Антон (LogRus), ну, скажем так, string - это аналог вектора с парочкой "но" :

1) свои методы, немного облегчающие работу со строками (хотя, до MFC::CString по удобству ему оооочень далеко Улыбаюсь )
2) всё-таки, string всегда принудительно ставит терминатор в конце данных.
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #79 : 03-09-2010 06:35 » 

не ставит он терминатор в конце данных, с чего ты взял
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #80 : 03-09-2010 07:16 » 

ну я же не задумываюсь об этом во время манипулирования со строками (в отличие от того, когда я использую для этого вектор), значит всё не просто так Улыбаюсь
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #81 : 03-09-2010 09:11 » 

Улыбаюсь ну это не означает, что они используют терминатор, значение длинны у них отдельным полем, есть нафига им терминатор.
Записан

Странно всё это....
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #82 : 03-09-2010 09:45 » 

нафига им терминатор.
Для корректного c_str()? Глянул исходник в VS 2008 - там при append вызывается функция:
Код:
void __CLR_OR_THIS_CALL _Eos(size_type _Newsize)
{ // set new length and null terminator
_Traits::assign(_Myptr()[_Mysize = _Newsize], _Elem());
}
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #83 : 03-09-2010 10:03 » 

Для корректного c_str()
о, да ) Я забыл упомянуть это чудо
Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #84 : 04-09-2010 17:46 » 

c_str это преобразование string к null terminated string
и к внутреннему представлению данных он имеет отношение опосредованное Улыбаюсь
если ты оперируешь только std::string, то этот терминатор может никогда не появится, поэтому не аргумент Улыбаюсь
Записан

Странно всё это....
lapulya
Молодой специалист

ru
Offline Offline

« Ответ #85 : 05-09-2010 20:34 » 

если не ошибаюсь, то стандартом не регламентировано использование или неиспользование терминаторора в std::string, поэтому тут все завист от реализации. В 99% случаев терминатор в реализации есть, но понятно, что полагаться на это нельзя.
Записан

С уважением Lapulya
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #86 : 05-09-2010 21:01 » 

если не ошибаюсь, то стандартом не регламентировано использование или неиспользование терминаторора в std::string, поэтому тут все завист от реализации. В 99% случаев терминатор в реализации есть, но понятно, что полагаться на это нельзя.
Или, говоря проще, если кто оперирует не-нуль-терминированными строками - тот сам себе злобный буратино. А предохранители вроде вышеуказанного у MS предназначены для снятия ответственности с поставщика библиотеки за отстреленные ноги Улыбаюсь
Записан
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #87 : 08-09-2010 08:17 » 

у bitset есть метод none, который, так понимаю, возвращает истину, когда все биты сброшены. А как определить, что все биты установлены? Можно, конечно, flip()+none()+flip(), но это же несерьёзно

Добавлено через 35 минут и 24 секунды:
о, count()==size() подходит Улыбаюсь
« Последнее редактирование: 08-09-2010 08:52 от Алексей1153 » Записан

Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #88 : 08-09-2010 08:54 » 

опередил Улыбаюсь
Записан

Странно всё это....
Алексей++
кот глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #89 : 08-09-2010 08:55 » 

но всё равно, поленились такой очевидный метод добавить

Добавлено через 13 дней, 9 часов, 9 минут и 22 секунды:
интересно, как-нибудь можно заставить std::search искать с конца, а не с начала ?
« Последнее редактирование: 21-09-2010 18:05 от Алексей1153 » Записан

Страниц: 1 2 [3] 4 5   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines