#ifndef _GLIBMM_SLISTHANDLE_H
#define _GLIBMM_SLISTHANDLE_H
/* Copyright (C) 2002 The gtkmm Development Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*/
#include
#include
#include
namespace Glib
{
namespace Container_Helpers
{
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* Create and fill a GSList as efficient as possible.
* This requires bidirectional iterators.
*/
template
GSList*
create_slist(Bi pbegin, Bi pend, Tr)
{
GSList* head = nullptr;
while (pend != pbegin)
{
// Use & to force a warning if the iterator returns a temporary object.
const void* const item = Tr::to_c_type(*&*--pend);
head = g_slist_prepend(head, const_cast(item));
}
return head;
}
/* Create a GSList from a 0-terminated input sequence.
* Build it in reverse order and reverse the whole list afterwards,
* because appending to the list would be horribly inefficient.
*/
template
GSList*
create_slist(For pbegin, Tr)
{
GSList* head = nullptr;
while (*pbegin)
{
// Use & to force a warning if the iterator returns a temporary object.
const void* const item = Tr::to_c_type(*&*pbegin);
head = g_slist_prepend(head, const_cast(item));
++pbegin;
}
return g_slist_reverse(head);
}
/* Convert from any container that supports bidirectional iterators.
*/
template
struct SListSourceTraits
{
static GSList* get_data(const Cont& cont)
{
return Glib::Container_Helpers::create_slist(cont.begin(), cont.end(), Tr());
}
static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
};
/* Convert from a 0-terminated array. The Cont
* argument must be a pointer to the first element.
*/
template
struct SListSourceTraits
{
static GSList* get_data(const Cont* array)
{
return (array) ? Glib::Container_Helpers::create_slist(array, Tr()) : nullptr;
}
static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
};
template
struct SListSourceTraits : SListSourceTraits
{
};
/* Convert from a 0-terminated array. The Cont argument must be a pointer
* to the first element. For consistency, the array must be 0-terminated,
* even though the array size is known at compile time.
*/
template
struct SListSourceTraits
{
static GSList* get_data(const Cont* array)
{
return Glib::Container_Helpers::create_slist(array, array + (N - 1), Tr());
}
static const Glib::OwnershipType initial_ownership = Glib::OWNERSHIP_SHALLOW;
};
template
struct SListSourceTraits : SListSourceTraits
{
};
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
/**
* @ingroup ContHelpers
*/
template
class SListHandleIterator
{
public:
using CppType = typename Tr::CppType;
using CType = typename Tr::CType;
using iterator_category = std::forward_iterator_tag;
using value_type = CppType;
using difference_type = std::ptrdiff_t;
using reference = value_type;
using pointer = void;
explicit inline SListHandleIterator(const GSList* node);
inline value_type operator*() const;
inline SListHandleIterator& operator++();
inline const SListHandleIterator
operator++(int);
inline bool operator==(const SListHandleIterator
& rhs) const;
inline bool operator!=(const SListHandleIterator
& rhs) const;
private:
const GSList* node_;
};
} // namespace Container_Helpers
// TODO: Remove this when we can break glibmm API.
/** This is an intermediate type. When a method takes this, or returns this, you
* should use a standard C++ container of your choice, such as std::list or
* std::vector.
*
* However, this is not used in new API. We now prefer to just use std::vector,
* which is less flexibile, but makes the API clearer.
* @ingroup ContHandles
*/
template >
class SListHandle
{
public:
using CppType = typename Tr::CppType;
using CType = typename Tr::CType;
using value_type = CppType;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using const_iterator = Glib::Container_Helpers::SListHandleIterator;
using iterator = Glib::Container_Helpers::SListHandleIterator
;
template
inline SListHandle(const Cont& container);
// Take over ownership of a GSList created by GTK+ functions.
inline SListHandle(GSList* glist, Glib::OwnershipType ownership);
// Copying clears the ownership flag of the source handle.
inline SListHandle(const SListHandle& other);
~SListHandle() noexcept;
inline const_iterator begin() const;
inline const_iterator end() const;
template
inline operator std::vector() const;
template
inline operator std::deque() const;
template
inline operator std::list() const;
template
inline void assign_to(Cont& container) const;
template
inline void copy(Out pdest) const;
inline GSList* data() const;
inline std::size_t size() const;
inline bool empty() const;
private:
GSList* pslist_;
mutable Glib::OwnershipType ownership_;
// No copy assignment.
SListHandle& operator=(const SListHandle&);
};
/***************************************************************************/
/* Inline implementation */
/***************************************************************************/
#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace Container_Helpers
{
/**** Glib::Container_Helpers::SListHandleIterator<> ***********************/
template
inline SListHandleIterator::SListHandleIterator(const GSList* node) : node_(node)
{
}
template
inline typename SListHandleIterator::value_type SListHandleIterator
::operator*() const
{
return Tr::to_cpp_type(static_cast(node_->data));
}
template
inline SListHandleIterator& SListHandleIterator
::operator++()
{
node_ = node_->next;
return *this;
}
template
inline const SListHandleIterator SListHandleIterator
::operator++(int)
{
const SListHandleIterator
tmp(*this);
node_ = node_->next;
return tmp;
}
template
inline bool
SListHandleIterator::operator==(const SListHandleIterator
& rhs) const
{
return (node_ == rhs.node_);
}
template
inline bool
SListHandleIterator::operator!=(const SListHandleIterator
& rhs) const
{
return (node_ != rhs.node_);
}
} // namespace Container_Helpers
/**** Glib::SListHandle<> **************************************************/
template
template
inline SListHandle::SListHandle(const Cont& container)
: pslist_(Glib::Container_Helpers::SListSourceTraits::get_data(container)),
ownership_(Glib::Container_Helpers::SListSourceTraits
::initial_ownership)
{
}
template
inline SListHandle::SListHandle(GSList* gslist, Glib::OwnershipType ownership)
: pslist_(gslist), ownership_(ownership)
{
}
template
inline SListHandle::SListHandle(const SListHandle& other)
: pslist_(other.pslist_), ownership_(other.ownership_)
{
other.ownership_ = Glib::OWNERSHIP_NONE;
}
template
SListHandle::~SListHandle() noexcept
{
if (ownership_ != Glib::OWNERSHIP_NONE)
{
if (ownership_ != Glib::OWNERSHIP_SHALLOW)
{
// Deep ownership: release each container element.
for (GSList* node = pslist_; node != nullptr; node = node->next)
Tr::release_c_type(static_cast(node->data));
}
g_slist_free(pslist_);
}
}
template
inline typename SListHandle::const_iterator
SListHandle::begin() const
{
return Glib::Container_Helpers::SListHandleIterator(pslist_);
}
template
inline typename SListHandle::const_iterator
SListHandle::end() const
{
return Glib::Container_Helpers::SListHandleIterator(nullptr);
}
template
template
inline SListHandle::operator std::vector() const
{
#ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
return std::vector(this->begin(), this->end());
#else
std::vector temp;
temp.reserve(this->size());
Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
return temp;
#endif
}
template
template
inline SListHandle::operator std::deque() const
{
#ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
return std::deque(this->begin(), this->end());
#else
std::deque temp;
Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
return temp;
#endif
}
template
template
inline SListHandle::operator std::list() const
{
#ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
return std::list(this->begin(), this->end());
#else
std::list temp;
Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
return temp;
#endif
}
template
template
inline void
SListHandle::assign_to(Cont& container) const
{
#ifdef GLIBMM_HAVE_TEMPLATE_SEQUENCE_CTORS
container.assign(this->begin(), this->end());
#else
Cont temp;
Glib::Container_Helpers::fill_container(temp, this->begin(), this->end());
container.swap(temp);
#endif
}
template
template
inline void
SListHandle::copy(Out pdest) const
{
std::copy(this->begin(), this->end(), pdest);
}
template
inline GSList*
SListHandle::data() const
{
return pslist_;
}
template
inline std::size_t
SListHandle::size() const
{
return g_slist_length(pslist_);
}
template
inline bool
SListHandle::empty() const
{
return (pslist_ == nullptr);
}
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
} // namespace Glib
#endif /* _GLIBMM_SLISTHANDLE_H */