Это перевернутый ответ. Вместо того, чтобы встраивать «эти объекты нужно синхронизировать» в качестве базы этого типа, вместо этого вставляйте под любым типом.
Вы имеете дело с синхронизированным объектом по-разному. Одна из серьезных проблем - вы должны беспокоиться о взаимоблокировках (блокировка нескольких объектов). Это также никогда не должно быть вашей «стандартной версией объекта»: синхронизированные объекты предназначены для объектов, которые будут в конфликте, и ваша цель должна заключаться в том, чтобы свести к минимуму конфликт между потоками, а не подметать его под ковер.
Но синхронизация объектов по-прежнему полезна. Вместо наследования от синхронизатора мы можем написать класс, который обертывает произвольный тип при синхронизации. Пользователи должны перейти через несколько обручей, чтобы выполнять операции над объектом теперь, когда они синхронизированы, но они не ограничены каким-то ограниченным набором операций с ограниченным ручным управлением для объекта. Они могут составлять несколько операций над объектом в один или работать с несколькими объектами.
Вот синхронизированная обертка вокруг произвольного типа T
:
template
struct synchronized {
template
auto read(F&& f) const&->std::result_of_t {
return access(std::forward(f), *this);
}
template
auto read(F&& f) &&->std::result_of_t {
return access(std::forward(f), std::move(*this));
}
template
auto write(F&& f)->std::result_of_t {
return access(std::forward(f), *this);
}
// uses `const` ness of Syncs to determine access:
template
friend auto access( F&& f, Syncs&&... syncs )->
std::result_of_t< F(decltype(std::forward(syncs).t)...) >
{
return access2( std::index_sequence_for{}, std::forward(f), std::forward(syncs)... );
};
synchronized(synchronized const& o):t(o.read([](T const&o){return o;})){}
synchronized(synchronized && o):t(std::move(o).read([](T&&o){return std::move(o);})){}
// special member functions:
synchronized( T & o ):t(o) {}
synchronized( T const& o ):t(o) {}
synchronized( T && o ):t(std::move(o)) {}
synchronized( T const&& o ):t(std::move(o)) {}
synchronized& operator=(T const& o) {
write([&](T& t){
t=o;
});
return *this;
}
synchronized& operator=(T && o) {
write([&](T& t){
t=std::move(o);
});
return *this;
}
private:
template
static auto smart_lock(S const& s) {
return std::shared_lock< std::shared_timed_mutex >(s.m, X{});
}
template
static auto smart_lock(S& s) {
return std::unique_lock< std::shared_timed_mutex >(s.m, X{});
}
template
static void lock(L& lockable) {
lockable.lock();
}
template
static void lock(Ls&... lockable) {
std::lock( lockable... );
}
template
friend auto access2( std::index_sequence, F&&f, Syncs&&...syncs)->
std::result_of_t< F(decltype(std::forward(syncs).t)...) >
{
auto locks = std::make_tuple( smart_lock(syncs)... );
lock( std::get(locks)... );
return std::forward(f)(std::forward(syncs).t ...);
}
mutable std::shared_timed_mutex m;
T t;
};
template
synchronized< T > sync( T&& t ) {
return {std::forward(t)};
}
C ++ 14 и C ++ 1z.
это предполагает, что операции const
являются безопасными с несколькими считывателями (что предполагает контейнер std
).
Использовать внешний вид например:
synchronized x = 7;
x.read([&](auto&& v){
std::cout << v << '\n';
});
для int
с синхронизированным доступом.
Я бы посоветовал не иметь synchronized(synchronized const&)
. Это редко бывает необходимо.
Если вам нужно synchronized(synchronized const&)
, у меня возникнет соблазн заменить T t;
на std::aligned_storage
, разрешить конструкцию ручного размещения и ручное уничтожение. Это позволяет правильное управление жизненным циклом.
Если это не удалось, мы могли бы скопировать источник T
, а затем прочитать из него:
synchronized(synchronized const& o):
t(o.read(
[](T const&o){return o;})
)
{}
synchronized(synchronized && o):
t(std::move(o).read(
[](T&&o){return std::move(o);})
)
{}
для назначения:
synchronized& operator=(synchronized const& o) {
access([](T& lhs, T const& rhs){
lhs = rhs;
}, *this, o);
return *this;
}
synchronized& operator=(synchronized && o) {
access([](T& lhs, T&& rhs){
lhs = std::move(rhs);
}, *this, std::move(o));
return *this;
}
friend void swap(synchronized& lhs, synchronized& rhs) {
access([](T& lhs, T& rhs){
using std::swap;
swap(lhs, rhs);
}, *this, o);
}
размещение и выровненные версии хранилищ немного беспорядочны. В большинстве случаев доступ к t
будет заменен на функцию-член T&t()
и T const&t()const
, за исключением конструкции, где вам придется перепрыгивать через некоторые обручи.
Сделав synchronized
вместо обертки части класса, все, что мы должны убедиться, состоит в том, что класс внутренне уважает const
как многократный читатель и записывает его однопоточным способом.
В редких случаях нам нужно синхронизированный экземпляр, мы прыгаем через обручи, как показано выше.
Извините за любые опечатки в приведенном выше. Вероятно, есть некоторые.
. Преимущество вышеизложенного заключается в том, что n-арные произвольные операции над объектами synchronized
(одного и того же типа) работают вместе, без необходимости жестко кодировать их перед началом работы. Добавить в объявление друга и n-ary synchronized
объекты нескольких типов могут работать вместе. Мне может потребоваться переместить access
из встроенного друга, чтобы иметь дело с перегрузками в этом случае.
Вы можете легко использовать метод Javascript .Split()
, чтобы разделить строки на слова, а затем найти первый символ. Например:
$('li').each(function(e) {
//Get full string as words
var words = $(this).text().split(" ");
for (var i = 0; i < words.length; i++) {
if (words[i].charAt(0) == "#") {
words[i] = "<span class=hashtag >" + words[i] + "</span>";
}
if (words[i].charAt(0) == "@") {
words[i] = "<span class=at >" + words[i] + "</span>";
}
}
$(this).html(words.join(" "));
});
.at {
color: red;
}
.hashtag {
color: blue
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<li>I am a #hashtag</li>
<li>Hey @Bill, what's your #dog called?</li>
<li>Try to only process #letters, #numbers, and not #punctuation.</li>
Примечание: я сделал это, используя простой метод. Вам нужно будет обработать слова, чтобы обнаружить, что они являются буквами / цифрами и не содержат других символов.
Вы также можете использовать match()
для поиска ваших at
и hash
слов.
let myhtml = $('ul').html();
const mytypes = myhtml.match(/(@|#)+[^\s<\.]+/g);
const myReplace = (mytype) => {
const isat = mytype.includes('@');
const replacestring = `<span class="${isat ? 'at' : 'hash'}">${mytype}</span>`;
myhtml = myhtml.replace(mytype, replacestring);
};
mytypes.forEach(el => myReplace(el));
$('ul').html(myhtml);
.at {
color: red;
}
.hash {
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li>Phone call @Mary #group-project</li>
<li>Buy food and drinks #BBQ.</li>
<li>Discard old computer #home #computer</li>
</ul>