Extract "external field" approach in a reusable class

Add wxExternalField<> template that can be used for other fields and/or
in other ports too.
This commit is contained in:
Vadim Zeitlin
2017-11-22 00:06:37 +01:00
parent 9cb1f25a25
commit 6fd435b83f
2 changed files with 105 additions and 60 deletions

View File

@@ -0,0 +1,84 @@
///////////////////////////////////////////////////////////////////////////////
// Name: wx/private/extfield.h
// Purpose: Declare wxExternalField helper
// Author: Vadim Zeitlin
// Created: 2017-11-21
// Copyright: (c) 2017 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_PRIVATE_EXTFIELD_H_
#define _WX_PRIVATE_EXTFIELD_H_
// ----------------------------------------------------------------------------
// wxExternalField: store object data outside of it
// ----------------------------------------------------------------------------
// This class allows to store some data without consuming space for the objects
// that don't need it and can be useful for avoiding to add rarely used fields
// to the classes that are used by many objects, e.g. wxWindow.
//
// Note that using this class costs in speed and convenience of access to the
// field, which requires a hash lookup instead of accessing it directly. It
// also only currently works for heap-allocated fields as it's probably never
// worth using it for fields of simple types.
//
// Template parameter Object is the class that "contains" the field, Field is
// the type of the field itself and FieldMap is the hash map, defined
// separately using WX_DECLARE_HASH_MAP(), with Object* as the key and Field*
// as the value type.
template <typename Object, typename Field, typename FieldMap>
class wxExternalField
{
public:
typedef Object ObjectType;
typedef Field FieldType;
typedef FieldMap MapType;
// Store the field object to be used for the given object, replacing the
// existing one, if any.
//
// This method takes ownership of the field pointer which will be destroyed
// by EraseForWindow().
static void StoreForWindow(ObjectType* obj, FieldType* field)
{
const typename MapType::iterator it = ms_map.find(obj);
if ( it != ms_map.end() )
{
delete it->second;
it->second = field;
}
else
{
ms_map.insert(typename MapType::value_type(obj, field));
}
}
// Find the object for the corresponding window.
static FieldType* FromWindow(ObjectType* obj)
{
const typename MapType::const_iterator it = ms_map.find(obj);
return it == ms_map.end() ? NULL : it->second;
}
// Erase the object used for the corresponding window, return true if there
// was one or false otherwise.
static bool EraseForWindow(ObjectType* obj)
{
const typename MapType::iterator it = ms_map.find(obj);
if ( it == ms_map.end() )
return false;
delete it->second;
ms_map.erase(it);
return true;
}
private:
static FieldMap ms_map;
};
template <typename O, typename F, typename M>
M wxExternalField<O, F, M>::ms_map;
#endif // _WX_PRIVATE_EXTFIELD_H_

View File

@@ -24,7 +24,6 @@
#endif #endif
#include "wx/evtloop.h" #include "wx/evtloop.h"
#include "wx/hashmap.h"
#if wxUSE_CARET #if wxUSE_CARET
#include "wx/caret.h" #include "wx/caret.h"
@@ -1502,11 +1501,6 @@ void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
class wxCocoaGesturesImpl;
WX_DECLARE_HASH_MAP(wxWidgetCocoaImpl*, wxCocoaGesturesImpl*,
wxPointerHash, wxPointerEqual,
wxCocoaGesturesImplMap);
// Class containing data used for gestures support. // Class containing data used for gestures support.
class wxCocoaGesturesImpl class wxCocoaGesturesImpl
{ {
@@ -1602,58 +1596,11 @@ public:
[m_initialTouch release]; [m_initialTouch release];
} }
// We keep all existing wxCocoaGesturesImpl objects in a
// wxWidgetCocoaImpl-indexed map. We do this instead of just having a data
// member containing wxCocoaGesturesImpl pointer in wxWidgetCocoaImpl
// itself because most windows don't need it and it seems wasteful to
// always increase their size unnecessarily.
// Store the object to be used for the given window, replacing the existing
// one, if any.
//
// This method takes ownership of wxCocoaGesturesImpl pointer which will be
// destroyed by EraseForWindow().
static void StoreForWindow(wxWidgetCocoaImpl* impl, wxCocoaGesturesImpl* obj)
{
const wxCocoaGesturesImplMap::iterator it = ms_map.find(impl);
if ( it != ms_map.end() )
{
delete it->second;
it->second = obj;
}
else
{
ms_map.insert(wxCocoaGesturesImplMap::value_type(impl, obj));
}
}
// Find the object for the corresponding window.
static wxCocoaGesturesImpl* FromWindow(wxWidgetCocoaImpl* impl)
{
const wxCocoaGesturesImplMap::const_iterator it = ms_map.find(impl);
return it == ms_map.end() ? NULL : it->second;
}
// Erase the object used for the corresponding window, return true if there
// was one or false otherwise.
static bool EraseForWindow(wxWidgetCocoaImpl* impl)
{
const wxCocoaGesturesImplMap::iterator it = ms_map.find(impl);
if ( it == ms_map.end() )
return false;
delete it->second;
ms_map.erase(it);
return true;
}
void TouchesBegan(NSEvent* event); void TouchesBegan(NSEvent* event);
void TouchesMoved(NSEvent* event); void TouchesMoved(NSEvent* event);
void TouchesEnded(NSEvent* event); void TouchesEnded(NSEvent* event);
private: private:
static wxCocoaGesturesImplMap ms_map;
wxWindowMac* const m_win; wxWindowMac* const m_win;
NSView* const m_view; NSView* const m_view;
@@ -1673,7 +1620,21 @@ private:
wxDECLARE_NO_COPY_CLASS(wxCocoaGesturesImpl); wxDECLARE_NO_COPY_CLASS(wxCocoaGesturesImpl);
}; };
wxCocoaGesturesImplMap wxCocoaGesturesImpl::ms_map; // We keep all existing wxCocoaGesturesImpl objects in a
// wxWidgetCocoaImpl-indexed map. We do this instead of just having a data
// member containing wxCocoaGesturesImpl pointer in wxWidgetCocoaImpl
// itself because most windows don't need it and it seems wasteful to
// always increase their size unnecessarily.
#include "wx/hashmap.h"
WX_DECLARE_HASH_MAP(wxWidgetCocoaImpl*, wxCocoaGesturesImpl*,
wxPointerHash, wxPointerEqual,
wxCocoaGesturesImplMap);
#include "wx/private/extfield.h"
typedef wxExternalField<wxWidgetCocoaImpl,
wxCocoaGesturesImpl,
wxCocoaGesturesImplMap> wxCocoaGestures;
void wxWidgetCocoaImpl::PanGestureEvent(NSPanGestureRecognizer* panGestureRecognizer) void wxWidgetCocoaImpl::PanGestureEvent(NSPanGestureRecognizer* panGestureRecognizer)
{ {
@@ -1875,7 +1836,7 @@ enum TrackedGestures
void wxWidgetCocoaImpl::TouchesBegan(WX_NSEvent event) void wxWidgetCocoaImpl::TouchesBegan(WX_NSEvent event)
{ {
if ( wxCocoaGesturesImpl* gestures = wxCocoaGesturesImpl::FromWindow(this) ) if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromWindow(this) )
gestures->TouchesBegan(event); gestures->TouchesBegan(event);
} }
@@ -1932,7 +1893,7 @@ void wxCocoaGesturesImpl::TouchesBegan(NSEvent* event)
void wxWidgetCocoaImpl::TouchesMoved(WX_NSEvent event) void wxWidgetCocoaImpl::TouchesMoved(WX_NSEvent event)
{ {
if ( wxCocoaGesturesImpl* gestures = wxCocoaGesturesImpl::FromWindow(this) ) if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromWindow(this) )
gestures->TouchesMoved(event); gestures->TouchesMoved(event);
} }
@@ -1988,7 +1949,7 @@ void wxCocoaGesturesImpl::TouchesMoved(NSEvent* event)
void wxWidgetCocoaImpl::TouchesEnded(WX_NSEvent event) void wxWidgetCocoaImpl::TouchesEnded(WX_NSEvent event)
{ {
if ( wxCocoaGesturesImpl* gestures = wxCocoaGesturesImpl::FromWindow(this) ) if ( wxCocoaGesturesImpl* gestures = wxCocoaGestures::FromWindow(this) )
gestures->TouchesEnded(event); gestures->TouchesEnded(event);
} }
@@ -2540,7 +2501,7 @@ wxWidgetCocoaImpl::~wxWidgetCocoaImpl()
CFRelease(m_osxView); CFRelease(m_osxView);
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
wxCocoaGesturesImpl::EraseForWindow(this); wxCocoaGestures::EraseForWindow(this);
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
} }
@@ -3469,7 +3430,7 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
{ {
if ( eventsMask == wxTOUCH_NONE ) if ( eventsMask == wxTOUCH_NONE )
{ {
if ( wxCocoaGesturesImpl::EraseForWindow(this) ) if ( wxCocoaGestures::EraseForWindow(this) )
{ {
[m_osxView setAcceptsTouchEvents:NO]; [m_osxView setAcceptsTouchEvents:NO];
} }
@@ -3477,7 +3438,7 @@ bool wxWidgetCocoaImpl::EnableTouchEvents(int eventsMask)
} }
else // We do want to have gesture events. else // We do want to have gesture events.
{ {
wxCocoaGesturesImpl::StoreForWindow wxCocoaGestures::StoreForWindow
( (
this, this,
new wxCocoaGesturesImpl(this, m_osxView, eventsMask) new wxCocoaGesturesImpl(this, m_osxView, eventsMask)