Bug 669040 part 1: Move mozilla/db/ to comm-central/db/ r=Standard8
--HG-- extra : rebase_source : 75fdd7282cbae578ca92c2034568afcb5b9e5fcb
This commit is contained in:
Родитель
90593898d4
Коммит
3d6edaf91b
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
ifndef NSS_DISABLE_DBM
|
||||
ifdef MOZ_MORK
|
||||
PARALLEL_DIRS = mork
|
||||
endif
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
|
@ -0,0 +1,48 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = src build public
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = mork
|
||||
LIBRARY_NAME = mork
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
MODULE_NAME = nsMorkModule
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
CPPSRCS = nsMorkFactory.cpp
|
||||
|
||||
EXPORTS = \
|
||||
nsMorkCID.h \
|
||||
nsIMdbFactoryFactory.h \
|
||||
$(NULL)
|
||||
|
||||
SHARED_LIBRARY_LIBS = ../src/$(LIB_PREFIX)msgmork_s.$(LIB_SUFFIX)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsIMdbFactoryFactory_h__
|
||||
#define nsIMdbFactoryFactory_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIComponentManager.h"
|
||||
|
||||
class nsIMdbFactory;
|
||||
|
||||
// 2794D0B7-E740-47a4-91C0-3E4FCB95B806
|
||||
#define NS_IMDBFACTORYFACTORY_IID \
|
||||
{ 0x2794d0b7, 0xe740, 0x47a4, { 0x91, 0xc0, 0x3e, 0x4f, 0xcb, 0x95, 0xb8, 0x6 } }
|
||||
|
||||
// because Mork doesn't support XPCOM, we have to wrap the mdb factory interface
|
||||
// with an interface that gives you an mdb factory.
|
||||
class nsIMdbFactoryService : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IMDBFACTORYFACTORY_IID)
|
||||
NS_IMETHOD GetMdbFactory(nsIMdbFactory **aFactory) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIMdbFactoryService, NS_IMDBFACTORYFACTORY_IID)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsMorkCID_h__
|
||||
#define nsMorkCID_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIComponentManager.h"
|
||||
|
||||
#define NS_MORK_CONTRACTID \
|
||||
"@mozilla.org/db/mork;1"
|
||||
|
||||
// 36d90300-27f5-11d3-8d74-00805f8a6617
|
||||
#define NS_MORK_CID \
|
||||
{ 0x36d90300, 0x27f5, 0x11d3, \
|
||||
{ 0x8d, 0x74, 0x00, 0x80, 0x5f, 0x8a, 0x66, 0x17 } }
|
||||
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsMorkCID.h"
|
||||
#include "nsIMdbFactoryFactory.h"
|
||||
#include "mdb.h"
|
||||
|
||||
class nsMorkFactoryService : public nsIMdbFactoryService
|
||||
{
|
||||
public:
|
||||
nsMorkFactoryService() {};
|
||||
// nsISupports methods
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD GetMdbFactory(nsIMdbFactory **aFactory);
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIMdbFactory> mMdbFactory;
|
||||
};
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsMorkFactoryService)
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_MORK_CID);
|
||||
|
||||
const mozilla::Module::CIDEntry kMorkCIDs[] = {
|
||||
{ &kNS_MORK_CID, false, NULL, nsMorkFactoryServiceConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
const mozilla::Module::ContractIDEntry kMorkContracts[] = {
|
||||
{ NS_MORK_CONTRACTID, &kNS_MORK_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kMorkModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kMorkCIDs,
|
||||
kMorkContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(nsMorkModule) = &kMorkModule;
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsMorkFactoryService, nsIMdbFactoryService)
|
||||
|
||||
NS_IMETHODIMP nsMorkFactoryService::GetMdbFactory(nsIMdbFactory **aFactory)
|
||||
{
|
||||
if (!mMdbFactory)
|
||||
mMdbFactory = MakeMdbFactory();
|
||||
NS_IF_ADDREF(*aFactory = mMdbFactory);
|
||||
return *aFactory ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1999
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = mork
|
||||
XPIDL_MODULE = msgmdb
|
||||
|
||||
EXPORTS = mdb.h
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,100 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = mork
|
||||
LIBRARY_NAME = msgmork_s
|
||||
FORCE_STATIC_LIB=1
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
CPPSRCS = \
|
||||
orkinHeap.cpp \
|
||||
morkArray.cpp \
|
||||
morkAtom.cpp \
|
||||
morkAtomMap.cpp \
|
||||
morkAtomSpace.cpp \
|
||||
morkBlob.cpp \
|
||||
morkBuilder.cpp \
|
||||
morkCell.cpp \
|
||||
morkCellObject.cpp \
|
||||
morkCh.cpp \
|
||||
morkConfig.cpp \
|
||||
morkCursor.cpp \
|
||||
morkDeque.cpp \
|
||||
morkEnv.cpp \
|
||||
morkFactory.cpp \
|
||||
morkFile.cpp \
|
||||
morkHandle.cpp \
|
||||
morkIntMap.cpp \
|
||||
morkMap.cpp \
|
||||
morkNode.cpp \
|
||||
morkNodeMap.cpp \
|
||||
morkObject.cpp \
|
||||
morkParser.cpp \
|
||||
morkPool.cpp \
|
||||
morkRow.cpp \
|
||||
morkRowCellCursor.cpp \
|
||||
morkRowMap.cpp \
|
||||
morkRowObject.cpp \
|
||||
morkRowSpace.cpp \
|
||||
morkSink.cpp \
|
||||
morkSpace.cpp \
|
||||
morkStore.cpp \
|
||||
morkStream.cpp \
|
||||
morkTable.cpp \
|
||||
morkPortTableCursor.cpp \
|
||||
morkTableRowCursor.cpp \
|
||||
morkThumb.cpp \
|
||||
morkWriter.cpp \
|
||||
morkYarn.cpp \
|
||||
morkBead.cpp \
|
||||
morkProbeMap.cpp \
|
||||
morkZone.cpp \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
CPPSRCS += morkSearchRowCursor.cpp
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORK_
|
||||
#define _MORK_ 1
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#include "nscore.h"
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
// { %%%%% begin disable unused param warnings %%%%%
|
||||
#define MORK_USED_1(x) (void)(&x)
|
||||
#define MORK_USED_2(x,y) (void)(&x);(void)(&y);
|
||||
#define MORK_USED_3(x,y,z) (void)(&x);(void)(&y);(void)(&z);
|
||||
#define MORK_USED_4(w,x,y,z) (void)(&w);(void)(&x);(void)(&y);(void)(&z);
|
||||
|
||||
// } %%%%% end disable unused param warnings %%%%%
|
||||
|
||||
// { %%%%% begin macro for finding class member offset %%%%%
|
||||
|
||||
/*| OffsetOf: the unsigned integer offset of a class or struct
|
||||
**| field from the beginning of that class or struct. This is
|
||||
**| the same as the similarly named public domain IronDoc macro,
|
||||
**| and is also the same as another macro appearing in stdlib.h.
|
||||
**| We want these offsets so we can correctly convert pointers
|
||||
**| to member slots back into pointers to enclosing objects, and
|
||||
**| have this exactly match what the compiler thinks is true.
|
||||
**|
|
||||
**|| Bascially we are asking the compiler to determine the offset at
|
||||
**| compile time, and we use the definition of address artithmetic
|
||||
**| to do this. By casting integer zero to a pointer of type obj*,
|
||||
**| we can reference the address of a slot in such an object that
|
||||
**| is hypothetically physically placed at address zero, but without
|
||||
**| actually dereferencing a memory location. The absolute address
|
||||
**| of slot is the same as offset of that slot, when the object is
|
||||
**| placed at address zero.
|
||||
|*/
|
||||
#define mork_OffsetOf(obj,slot) ((unsigned int)&((obj*) 0)->slot)
|
||||
|
||||
// } %%%%% end macro for finding class member offset %%%%%
|
||||
|
||||
// { %%%%% begin specific-size integer scalar typedefs %%%%%
|
||||
typedef unsigned char mork_u1; // make sure this is one byte
|
||||
typedef unsigned short mork_u2; // make sure this is two bytes
|
||||
typedef short mork_i2; // make sure this is two bytes
|
||||
typedef PRUint32 mork_u4; // make sure this is four bytes
|
||||
typedef PRInt32 mork_i4; // make sure this is four bytes
|
||||
typedef PRWord mork_ip; // make sure sizeof(mork_ip) == sizeof(void*)
|
||||
|
||||
typedef mork_u1 mork_ch; // small byte-sized character (never wide)
|
||||
typedef mork_u1 mork_flags; // one byte's worth of predicate bit flags
|
||||
|
||||
typedef mork_u2 mork_base; // 2-byte magic class signature slot in object
|
||||
typedef mork_u2 mork_derived; // 2-byte magic class signature slot in object
|
||||
typedef mork_u2 mork_uses; // 2-byte strong uses count
|
||||
typedef mork_u2 mork_refs; // 2-byte actual reference count
|
||||
|
||||
typedef mork_u4 mork_token; // unsigned token for atomized string
|
||||
typedef mork_token mork_scope; // token used to id scope for rows
|
||||
typedef mork_token mork_kind; // token used to id kind for tables
|
||||
typedef mork_token mork_cscode; // token used to id charset names
|
||||
typedef mork_token mork_aid; // token used to id atomize cell values
|
||||
|
||||
typedef mork_token mork_column; // token used to id columns for rows
|
||||
typedef mork_column mork_delta; // mork_column plus mork_change
|
||||
|
||||
typedef mork_token mork_color; // bead ID
|
||||
#define morkColor_kNone ((mork_color) 0)
|
||||
|
||||
typedef mork_u4 mork_magic; // unsigned magic signature
|
||||
|
||||
typedef mork_u4 mork_seed; // unsigned collection change counter
|
||||
typedef mork_u4 mork_count; // unsigned collection member count
|
||||
typedef mork_count mork_num; // synonym for count
|
||||
typedef mork_u4 mork_size; // unsigned physical media size
|
||||
typedef mork_u4 mork_fill; // unsigned logical content size
|
||||
typedef mork_u4 mork_more; // more available bytes for larger buffer
|
||||
|
||||
typedef mdb_u4 mork_percent; // 0..100, with values >100 same as 100
|
||||
|
||||
typedef mork_i4 mork_pos; // negative means "before first" (at zero pos)
|
||||
typedef mork_i4 mork_line; // negative means "before first line in file"
|
||||
|
||||
typedef mork_u1 mork_usage; // 1-byte magic usage signature slot in object
|
||||
typedef mork_u1 mork_access; // 1-byte magic access signature slot in object
|
||||
|
||||
typedef mork_u1 mork_change; // add, cut, put, set, nil
|
||||
typedef mork_u1 mork_priority; // 0..9, for a total of ten different values
|
||||
|
||||
typedef mork_u1 mork_able; // on, off, asleep (clone IronDoc's fe_able)
|
||||
typedef mork_u1 mork_load; // dirty or clean (clone IronDoc's fe_load)
|
||||
// } %%%%% end specific-size integer scalar typedefs %%%%%
|
||||
|
||||
// 'test' is a public domain Mithril for key equality tests in probe maps
|
||||
typedef mork_i2 mork_test; /* neg=>kVoid, zero=>kHit, pos=>kMiss */
|
||||
|
||||
#define morkTest_kVoid ((mork_test) -1) /* -1: nil key slot, no key order */
|
||||
#define morkTest_kHit ((mork_test) 0) /* 0: keys are equal, a map hit */
|
||||
#define morkTest_kMiss ((mork_test) 1) /* 1: keys not equal, a map miss */
|
||||
|
||||
// { %%%%% begin constants for Mork scalar types %%%%%
|
||||
#define morkPriority_kHi ((mork_priority) 0) /* best priority */
|
||||
#define morkPriority_kMin ((mork_priority) 0) /* best priority is smallest */
|
||||
|
||||
#define morkPriority_kLo ((mork_priority) 9) /* worst priority */
|
||||
#define morkPriority_kMax ((mork_priority) 9) /* worst priority is biggest */
|
||||
|
||||
#define morkPriority_kCount 10 /* number of distinct priority values */
|
||||
|
||||
#define morkAble_kEnabled ((mork_able) 0x55) /* same as IronDoc constant */
|
||||
#define morkAble_kDisabled ((mork_able) 0xAA) /* same as IronDoc constant */
|
||||
#define morkAble_kAsleep ((mork_able) 0x5A) /* same as IronDoc constant */
|
||||
|
||||
#define morkChange_kAdd 'a' /* add member */
|
||||
#define morkChange_kCut 'c' /* cut member */
|
||||
#define morkChange_kPut 'p' /* put member */
|
||||
#define morkChange_kSet 's' /* set all members */
|
||||
#define morkChange_kNil 0 /* no change in this member */
|
||||
#define morkChange_kDup 'd' /* duplicate changes have no effect */
|
||||
// kDup is intended to replace another change constant in an object as a
|
||||
// conclusion about change feasibility while staging intended alterations.
|
||||
|
||||
#define morkLoad_kDirty ((mork_load) 0xDD) /* same as IronDoc constant */
|
||||
#define morkLoad_kClean ((mork_load) 0x22) /* same as IronDoc constant */
|
||||
|
||||
#define morkAccess_kOpen 'o'
|
||||
#define morkAccess_kClosing 'c'
|
||||
#define morkAccess_kShut 's'
|
||||
#define morkAccess_kDead 'd'
|
||||
// } %%%%% end constants for Mork scalar types %%%%%
|
||||
|
||||
// { %%%%% begin non-specific-size integer scalar typedefs %%%%%
|
||||
typedef int mork_char; // nominal type for ints used to hold input byte
|
||||
#define morkChar_IsWhite(c) \
|
||||
((c) == 0xA || (c) == 0x9 || (c) == 0xD || (c) == ' ')
|
||||
// } %%%%% end non-specific-size integer scalar typedefs %%%%%
|
||||
|
||||
// { %%%%% begin mdb-driven scalar typedefs %%%%%
|
||||
// easier to define bool exactly the same as mdb:
|
||||
typedef mdb_bool mork_bool; // unsigned byte with zero=false, nonzero=true
|
||||
|
||||
/* canonical boolean constants provided only for code clarity: */
|
||||
#define morkBool_kTrue ((mork_bool) 1) /* actually any nonzero means true */
|
||||
#define morkBool_kFalse ((mork_bool) 0) /* only zero means false */
|
||||
|
||||
// mdb clients can assign these, so we cannot pick maximum size:
|
||||
typedef mdb_id mork_id; // unsigned object identity in a scope
|
||||
typedef mork_id mork_rid; // unsigned row identity inside scope
|
||||
typedef mork_id mork_tid; // unsigned table identity inside scope
|
||||
typedef mork_id mork_gid; // unsigned group identity without any scope
|
||||
|
||||
// we only care about neg, zero, pos -- so we don't care about size:
|
||||
typedef mdb_order mork_order; // neg:lessthan, zero:equalto, pos:greaterthan
|
||||
// } %%%%% end mdb-driven scalar typedefs %%%%%
|
||||
|
||||
#define morkId_kMinusOne ((mdb_id) -1)
|
||||
|
||||
// { %%%%% begin class forward defines %%%%%
|
||||
// try to put these in alphabetical order for easier examination:
|
||||
class morkMid;
|
||||
class morkAtom;
|
||||
class morkAtomSpace;
|
||||
class morkBookAtom;
|
||||
class morkBuf;
|
||||
class morkBuilder;
|
||||
class morkCell;
|
||||
class morkCellObject;
|
||||
class morkCursor;
|
||||
class morkEnv;
|
||||
class morkFactory;
|
||||
class morkFile;
|
||||
class morkHandle;
|
||||
class morkHandleFace; // just an opaque cookie type
|
||||
class morkHandleFrame;
|
||||
class morkHashArrays;
|
||||
class morkMap;
|
||||
class morkNode;
|
||||
class morkObject;
|
||||
class morkOidAtom;
|
||||
class morkParser;
|
||||
class morkPool;
|
||||
class morkPlace;
|
||||
class morkPort;
|
||||
class morkPortTableCursor;
|
||||
class morkProbeMap;
|
||||
class morkRow;
|
||||
class morkRowCellCursor;
|
||||
class morkRowObject;
|
||||
class morkRowSpace;
|
||||
class morkSorting;
|
||||
class morkSortingRowCursor;
|
||||
class morkSpace;
|
||||
class morkSpan;
|
||||
class morkStore;
|
||||
class morkStream;
|
||||
class morkTable;
|
||||
class morkTableChange;
|
||||
class morkTableRowCursor;
|
||||
class morkThumb;
|
||||
class morkWriter;
|
||||
class morkZone;
|
||||
// } %%%%% end class forward defines %%%%%
|
||||
|
||||
// include this config file last for platform & environment specific stuff:
|
||||
#ifndef _MORKCONFIG_
|
||||
#include "morkConfig.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORK_ */
|
|
@ -0,0 +1,334 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nscore.h"
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKARRAY_
|
||||
#include "morkArray.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkArray::CloseMorkNode(morkEnv* ev) // CloseTable() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseArray(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkArray::~morkArray() // assert CloseTable() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
MORK_ASSERT(mArray_Slots==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkArray::morkArray(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, mork_size inSize, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
, mArray_Slots( 0 )
|
||||
, mArray_Heap( 0 )
|
||||
, mArray_Fill( 0 )
|
||||
, mArray_Size( 0 )
|
||||
, mArray_Seed( (mork_u4)NS_PTR_TO_INT32(this) ) // "random" integer assignment
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mArray_Heap);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( inSize < 3 )
|
||||
inSize = 3;
|
||||
mdb_size byteSize = inSize * sizeof(void*);
|
||||
void** block = 0;
|
||||
ioSlotHeap->Alloc(ev->AsMdbEnv(), byteSize, (void**) &block);
|
||||
if ( block && ev->Good() )
|
||||
{
|
||||
mArray_Slots = block;
|
||||
mArray_Size = inSize;
|
||||
MORK_MEMSET(mArray_Slots, 0, byteSize);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkArray::CloseArray(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( mArray_Heap && mArray_Slots )
|
||||
mArray_Heap->Free(ev->AsMdbEnv(), mArray_Slots);
|
||||
|
||||
mArray_Slots = 0;
|
||||
mArray_Size = 0;
|
||||
mArray_Fill = 0;
|
||||
++mArray_Seed;
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mArray_Heap);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkArray::NonArrayTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkArray");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkArray::IndexBeyondEndError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("array index beyond end");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkArray::NilSlotsAddressError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mArray_Slots");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkArray::FillBeyondSizeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mArray_Fill > mArray_Size");
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkArray::Grow(morkEnv* ev, mork_size inNewSize)
|
||||
// Grow() returns true if capacity becomes >= inNewSize and ev->Good()
|
||||
{
|
||||
if ( ev->Good() && inNewSize > mArray_Size ) // make array larger?
|
||||
{
|
||||
if ( mArray_Fill <= mArray_Size ) // fill and size fit the invariant?
|
||||
{
|
||||
if (mArray_Size <= 3)
|
||||
inNewSize = mArray_Size + 3;
|
||||
else
|
||||
inNewSize = mArray_Size * 2;// + 3; // try doubling size here - used to grow by 3
|
||||
|
||||
mdb_size newByteSize = inNewSize * sizeof(void*);
|
||||
void** newBlock = 0;
|
||||
mArray_Heap->Alloc(ev->AsMdbEnv(), newByteSize, (void**) &newBlock);
|
||||
if ( newBlock && ev->Good() ) // okay new block?
|
||||
{
|
||||
void** oldSlots = mArray_Slots;
|
||||
void** oldEnd = oldSlots + mArray_Fill;
|
||||
|
||||
void** newSlots = newBlock;
|
||||
void** newEnd = newBlock + inNewSize;
|
||||
|
||||
while ( oldSlots < oldEnd )
|
||||
*newSlots++ = *oldSlots++;
|
||||
|
||||
while ( newSlots < newEnd )
|
||||
*newSlots++ = (void*) 0;
|
||||
|
||||
oldSlots = mArray_Slots;
|
||||
mArray_Size = inNewSize;
|
||||
mArray_Slots = newBlock;
|
||||
mArray_Heap->Free(ev->AsMdbEnv(), oldSlots);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->FillBeyondSizeError(ev);
|
||||
}
|
||||
++mArray_Seed; // always modify seed, since caller intends to add slots
|
||||
return ( ev->Good() && mArray_Size >= inNewSize );
|
||||
}
|
||||
|
||||
void*
|
||||
morkArray::SafeAt(morkEnv* ev, mork_pos inPos)
|
||||
{
|
||||
if ( mArray_Slots )
|
||||
{
|
||||
if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
|
||||
return mArray_Slots[ inPos ];
|
||||
else
|
||||
this->IndexBeyondEndError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSlotsAddressError(ev);
|
||||
|
||||
return (void*) 0;
|
||||
}
|
||||
|
||||
void
|
||||
morkArray::SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot)
|
||||
{
|
||||
if ( mArray_Slots )
|
||||
{
|
||||
if ( inPos >= 0 && inPos < (mork_pos) mArray_Fill )
|
||||
{
|
||||
mArray_Slots[ inPos ] = ioSlot;
|
||||
++mArray_Seed;
|
||||
}
|
||||
else
|
||||
this->IndexBeyondEndError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSlotsAddressError(ev);
|
||||
}
|
||||
|
||||
mork_pos
|
||||
morkArray::AppendSlot(morkEnv* ev, void* ioSlot)
|
||||
{
|
||||
mork_pos outPos = -1;
|
||||
if ( mArray_Slots )
|
||||
{
|
||||
mork_fill fill = mArray_Fill;
|
||||
if ( this->Grow(ev, fill+1) )
|
||||
{
|
||||
outPos = (mork_pos) fill;
|
||||
mArray_Slots[ fill ] = ioSlot;
|
||||
mArray_Fill = fill + 1;
|
||||
// note Grow() increments mArray_Seed
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSlotsAddressError(ev);
|
||||
|
||||
return outPos;
|
||||
}
|
||||
|
||||
void
|
||||
morkArray::AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot)
|
||||
{
|
||||
if ( mArray_Slots )
|
||||
{
|
||||
mork_fill fill = mArray_Fill;
|
||||
if ( this->Grow(ev, fill+1) )
|
||||
{
|
||||
void** slot = mArray_Slots; // the slot vector
|
||||
void** end = slot + fill; // one past the last used array slot
|
||||
slot += inPos; // the slot to be added
|
||||
|
||||
while ( --end >= slot ) // another slot to move upward?
|
||||
end[ 1 ] = *end;
|
||||
|
||||
*slot = ioSlot;
|
||||
mArray_Fill = fill + 1;
|
||||
// note Grow() increments mArray_Seed
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSlotsAddressError(ev);
|
||||
}
|
||||
|
||||
void
|
||||
morkArray::CutSlot(morkEnv* ev, mork_pos inPos)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mork_fill fill = mArray_Fill;
|
||||
if ( inPos >= 0 && inPos < (mork_pos) fill ) // cutting slot in used array portion?
|
||||
{
|
||||
void** slot = mArray_Slots; // the slot vector
|
||||
void** end = slot + fill; // one past the last used array slot
|
||||
slot += inPos; // the slot to be cut
|
||||
|
||||
while ( ++slot < end ) // another slot to move downward?
|
||||
slot[ -1 ] = *slot;
|
||||
|
||||
slot[ -1 ] = 0; // clear the last used slot which is now unused
|
||||
|
||||
// note inPos<fill implies fill>0, so fill-1 must be nonnegative:
|
||||
mArray_Fill = fill - 1;
|
||||
++mArray_Seed;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkArray::CutAllSlots(morkEnv* ev)
|
||||
{
|
||||
if ( mArray_Slots )
|
||||
{
|
||||
if ( mArray_Fill <= mArray_Size )
|
||||
{
|
||||
mdb_size oldByteSize = mArray_Fill * sizeof(void*);
|
||||
MORK_MEMSET(mArray_Slots, 0, oldByteSize);
|
||||
}
|
||||
else
|
||||
this->FillBeyondSizeError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSlotsAddressError(ev);
|
||||
|
||||
++mArray_Seed;
|
||||
mArray_Fill = 0;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,130 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKARRAY_
|
||||
#define _MORKARRAY_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kArray /*i*/ 0x4179 /* ascii 'Ay' */
|
||||
|
||||
class morkArray : public morkNode { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
void** mArray_Slots; // array of pointers
|
||||
nsIMdbHeap* mArray_Heap; // required heap for allocating mArray_Slots
|
||||
mork_fill mArray_Fill; // logical count of used slots in mArray_Slots
|
||||
mork_size mArray_Size; // physical count of mArray_Slots ( >= Fill)
|
||||
mork_seed mArray_Seed; // change counter for syncing with iterators
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseArray()
|
||||
virtual ~morkArray(); // assert that close executed earlier
|
||||
|
||||
public: // morkArray construction & destruction
|
||||
morkArray(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, mork_size inSize, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseArray(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkArray(const morkArray& other);
|
||||
morkArray& operator=(const morkArray& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsArray() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kArray; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing & errors
|
||||
static void NonArrayTypeError(morkEnv* ev);
|
||||
static void IndexBeyondEndError(morkEnv* ev);
|
||||
static void NilSlotsAddressError(morkEnv* ev);
|
||||
static void FillBeyondSizeError(morkEnv* ev);
|
||||
|
||||
public: // other table row cursor methods
|
||||
|
||||
mork_fill Length() const { return mArray_Fill; }
|
||||
mork_size Capacity() const { return mArray_Size; }
|
||||
|
||||
mork_bool Grow(morkEnv* ev, mork_size inNewSize);
|
||||
// Grow() returns true if capacity becomes >= inNewSize and ev->Good()
|
||||
|
||||
void* At(mork_pos inPos) const { return mArray_Slots[ inPos ]; }
|
||||
void AtPut(mork_pos inPos, void* ioSlot)
|
||||
{ mArray_Slots[ inPos ] = ioSlot; }
|
||||
|
||||
void* SafeAt(morkEnv* ev, mork_pos inPos);
|
||||
void SafeAtPut(morkEnv* ev, mork_pos inPos, void* ioSlot);
|
||||
|
||||
mork_pos AppendSlot(morkEnv* ev, void* ioSlot);
|
||||
void AddSlot(morkEnv* ev, mork_pos inPos, void* ioSlot);
|
||||
void CutSlot(morkEnv* ev, mork_pos inPos);
|
||||
void CutAllSlots(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakArray(morkArray* me,
|
||||
morkEnv* ev, morkArray** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongArray(morkArray* me,
|
||||
morkEnv* ev, morkArray** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKTABLEROWCURSOR_ */
|
|
@ -0,0 +1,604 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#include "morkAtom.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMSPACE_
|
||||
#include "morkAtomSpace.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
mork_bool
|
||||
morkAtom::GetYarn(mdbYarn* outYarn) const
|
||||
{
|
||||
const void* source = 0;
|
||||
mdb_fill fill = 0;
|
||||
mdb_cscode form = 0;
|
||||
outYarn->mYarn_More = 0;
|
||||
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsWeeBook() )
|
||||
{
|
||||
morkWeeBookAtom* weeBook = (morkWeeBookAtom*) this;
|
||||
source = weeBook->mWeeBookAtom_Body;
|
||||
fill = weeBook->mAtom_Size;
|
||||
}
|
||||
else if ( this->IsBigBook() )
|
||||
{
|
||||
morkBigBookAtom* bigBook = (morkBigBookAtom*) this;
|
||||
source = bigBook->mBigBookAtom_Body;
|
||||
fill = bigBook->mBigBookAtom_Size;
|
||||
form = bigBook->mBigBookAtom_Form;
|
||||
}
|
||||
else if ( this->IsWeeAnon() )
|
||||
{
|
||||
morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) this;
|
||||
source = weeAnon->mWeeAnonAtom_Body;
|
||||
fill = weeAnon->mAtom_Size;
|
||||
}
|
||||
else if ( this->IsBigAnon() )
|
||||
{
|
||||
morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) this;
|
||||
source = bigAnon->mBigAnonAtom_Body;
|
||||
fill = bigAnon->mBigAnonAtom_Size;
|
||||
form = bigAnon->mBigAnonAtom_Form;
|
||||
}
|
||||
}
|
||||
if ( source && fill ) // have an atom with nonempty content?
|
||||
{
|
||||
// if we have too many bytes, and yarn seems growable:
|
||||
if ( fill > outYarn->mYarn_Size && outYarn->mYarn_Grow ) // try grow?
|
||||
(*outYarn->mYarn_Grow)(outYarn, (mdb_size) fill); // request bigger
|
||||
|
||||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much atom content?
|
||||
{
|
||||
outYarn->mYarn_More = fill - size; // extra atom bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
if ( !dest ) // nil destination address buffer?
|
||||
fill = 0; // we can't write any content at all
|
||||
|
||||
if ( fill ) // anything to copy?
|
||||
MORK_MEMCPY(dest, source, fill); // copy fill bytes to yarn
|
||||
|
||||
outYarn->mYarn_Fill = fill; // tell yarn size of copied content
|
||||
}
|
||||
else // no content to put into the yarn
|
||||
{
|
||||
outYarn->mYarn_Fill = 0; // tell yarn that atom has no bytes
|
||||
}
|
||||
outYarn->mYarn_Form = form; // always update the form slot
|
||||
|
||||
return ( source != 0 );
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkAtom::AsBuf(morkBuf& outBuf) const
|
||||
{
|
||||
const morkAtom* atom = this;
|
||||
if ( atom )
|
||||
{
|
||||
if ( atom->IsWeeBook() )
|
||||
{
|
||||
morkWeeBookAtom* weeBook = (morkWeeBookAtom*) atom;
|
||||
outBuf.mBuf_Body = weeBook->mWeeBookAtom_Body;
|
||||
outBuf.mBuf_Fill = weeBook->mAtom_Size;
|
||||
}
|
||||
else if ( atom->IsBigBook() )
|
||||
{
|
||||
morkBigBookAtom* bigBook = (morkBigBookAtom*) atom;
|
||||
outBuf.mBuf_Body = bigBook->mBigBookAtom_Body;
|
||||
outBuf.mBuf_Fill = bigBook->mBigBookAtom_Size;
|
||||
}
|
||||
else if ( atom->IsWeeAnon() )
|
||||
{
|
||||
morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) atom;
|
||||
outBuf.mBuf_Body = weeAnon->mWeeAnonAtom_Body;
|
||||
outBuf.mBuf_Fill = weeAnon->mAtom_Size;
|
||||
}
|
||||
else if ( atom->IsBigAnon() )
|
||||
{
|
||||
morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) atom;
|
||||
outBuf.mBuf_Body = bigAnon->mBigAnonAtom_Body;
|
||||
outBuf.mBuf_Fill = bigAnon->mBigAnonAtom_Size;
|
||||
}
|
||||
else
|
||||
atom = 0; // show desire to put empty content in yarn
|
||||
}
|
||||
|
||||
if ( !atom ) // empty content for yarn?
|
||||
{
|
||||
outBuf.mBuf_Body = 0;
|
||||
outBuf.mBuf_Fill = 0;
|
||||
}
|
||||
return ( atom != 0 );
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkAtom::AliasYarn(mdbYarn* outYarn) const
|
||||
{
|
||||
outYarn->mYarn_More = 0;
|
||||
outYarn->mYarn_Form = 0;
|
||||
const morkAtom* atom = this;
|
||||
|
||||
if ( atom )
|
||||
{
|
||||
if ( atom->IsWeeBook() )
|
||||
{
|
||||
morkWeeBookAtom* weeBook = (morkWeeBookAtom*) atom;
|
||||
outYarn->mYarn_Buf = weeBook->mWeeBookAtom_Body;
|
||||
outYarn->mYarn_Fill = weeBook->mAtom_Size;
|
||||
outYarn->mYarn_Size = weeBook->mAtom_Size;
|
||||
}
|
||||
else if ( atom->IsBigBook() )
|
||||
{
|
||||
morkBigBookAtom* bigBook = (morkBigBookAtom*) atom;
|
||||
outYarn->mYarn_Buf = bigBook->mBigBookAtom_Body;
|
||||
outYarn->mYarn_Fill = bigBook->mBigBookAtom_Size;
|
||||
outYarn->mYarn_Size = bigBook->mBigBookAtom_Size;
|
||||
outYarn->mYarn_Form = bigBook->mBigBookAtom_Form;
|
||||
}
|
||||
else if ( atom->IsWeeAnon() )
|
||||
{
|
||||
morkWeeAnonAtom* weeAnon = (morkWeeAnonAtom*) atom;
|
||||
outYarn->mYarn_Buf = weeAnon->mWeeAnonAtom_Body;
|
||||
outYarn->mYarn_Fill = weeAnon->mAtom_Size;
|
||||
outYarn->mYarn_Size = weeAnon->mAtom_Size;
|
||||
}
|
||||
else if ( atom->IsBigAnon() )
|
||||
{
|
||||
morkBigAnonAtom* bigAnon = (morkBigAnonAtom*) atom;
|
||||
outYarn->mYarn_Buf = bigAnon->mBigAnonAtom_Body;
|
||||
outYarn->mYarn_Fill = bigAnon->mBigAnonAtom_Size;
|
||||
outYarn->mYarn_Size = bigAnon->mBigAnonAtom_Size;
|
||||
outYarn->mYarn_Form = bigAnon->mBigAnonAtom_Form;
|
||||
}
|
||||
else
|
||||
atom = 0; // show desire to put empty content in yarn
|
||||
}
|
||||
|
||||
if ( !atom ) // empty content for yarn?
|
||||
{
|
||||
outYarn->mYarn_Buf = 0;
|
||||
outYarn->mYarn_Fill = 0;
|
||||
outYarn->mYarn_Size = 0;
|
||||
// outYarn->mYarn_Grow = 0; // please don't modify the Grow slot
|
||||
}
|
||||
return ( atom != 0 );
|
||||
}
|
||||
|
||||
mork_aid
|
||||
morkAtom::GetBookAtomAid() const // zero or book atom's ID
|
||||
{
|
||||
return ( this->IsBook() )? ((morkBookAtom*) this)->mBookAtom_Id : 0;
|
||||
}
|
||||
|
||||
mork_scope
|
||||
morkAtom::GetBookAtomSpaceScope(morkEnv* ev) const // zero or book's space's scope
|
||||
{
|
||||
mork_scope outScope = 0;
|
||||
if ( this->IsBook() )
|
||||
{
|
||||
const morkBookAtom* bookAtom = (const morkBookAtom*) this;
|
||||
morkAtomSpace* space = bookAtom->mBookAtom_Space;
|
||||
if ( space->IsAtomSpace() )
|
||||
outScope = space->SpaceScope();
|
||||
else
|
||||
space->NonAtomSpaceTypeError(ev);
|
||||
}
|
||||
|
||||
return outScope;
|
||||
}
|
||||
|
||||
void
|
||||
morkAtom::MakeCellUseForever(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mAtom_CellUses = morkAtom_kForeverCellUses;
|
||||
}
|
||||
|
||||
mork_u1
|
||||
morkAtom::AddCellUse(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
if ( mAtom_CellUses < morkAtom_kMaxCellUses ) // not already maxed out?
|
||||
++mAtom_CellUses;
|
||||
|
||||
return mAtom_CellUses;
|
||||
}
|
||||
|
||||
mork_u1
|
||||
morkAtom::CutCellUse(morkEnv* ev)
|
||||
{
|
||||
if ( mAtom_CellUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mAtom_CellUses < morkAtom_kMaxCellUses ) // not frozen at max?
|
||||
--mAtom_CellUses;
|
||||
}
|
||||
else
|
||||
this->CellUsesUnderflowWarning(ev);
|
||||
|
||||
return mAtom_CellUses;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkAtom::CellUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mAtom_CellUses underflow");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkAtom::BadAtomKindError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad mAtom_Kind");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkAtom::ZeroAidError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("zero atom ID");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkAtom::AtomSizeOverflowError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("atom mAtom_Size overflow");
|
||||
}
|
||||
|
||||
void
|
||||
morkOidAtom::InitRowOidAtom(morkEnv* ev, const mdbOid& inOid)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindRowOid;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
mAtom_Size = 0;
|
||||
mOidAtom_Oid = inOid; // bitwise copy
|
||||
}
|
||||
|
||||
void
|
||||
morkOidAtom::InitTableOidAtom(morkEnv* ev, const mdbOid& inOid)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindTableOid;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
mAtom_Size = 0;
|
||||
mOidAtom_Oid = inOid; // bitwise copy
|
||||
}
|
||||
|
||||
void
|
||||
morkWeeAnonAtom::InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf)
|
||||
{
|
||||
mAtom_Kind = 0;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
if ( inBuf.mBuf_Fill <= morkAtom_kMaxByteSize )
|
||||
{
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindWeeAnon;
|
||||
mork_size size = inBuf.mBuf_Fill;
|
||||
mAtom_Size = (mork_u1) size;
|
||||
if ( size && inBuf.mBuf_Body )
|
||||
MORK_MEMCPY(mWeeAnonAtom_Body, inBuf.mBuf_Body, size);
|
||||
|
||||
mWeeAnonAtom_Body[ size ] = 0;
|
||||
}
|
||||
else
|
||||
this->AtomSizeOverflowError(ev);
|
||||
}
|
||||
|
||||
void
|
||||
morkBigAnonAtom::InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindBigAnon;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
mAtom_Size = 0;
|
||||
mBigAnonAtom_Form = inForm;
|
||||
mork_size size = inBuf.mBuf_Fill;
|
||||
mBigAnonAtom_Size = size;
|
||||
if ( size && inBuf.mBuf_Body )
|
||||
MORK_MEMCPY(mBigAnonAtom_Body, inBuf.mBuf_Body, size);
|
||||
|
||||
mBigAnonAtom_Body[ size ] = 0;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkBookAtom::NonBookAtomTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkBookAtom");
|
||||
}
|
||||
|
||||
mork_u4
|
||||
morkBookAtom::HashFormAndBody(morkEnv* ev) const
|
||||
{
|
||||
// This hash is obviously a variation of the dragon book string hash.
|
||||
// (I won't bother to explain or rationalize this usage for you.)
|
||||
|
||||
register mork_u4 outHash = 0; // hash value returned
|
||||
register unsigned char c; // next character
|
||||
register const mork_u1* body; // body of bytes to hash
|
||||
mork_size size = 0; // the number of bytes to hash
|
||||
|
||||
if ( this->IsWeeBook() )
|
||||
{
|
||||
size = mAtom_Size;
|
||||
body = ((const morkWeeBookAtom*) this)->mWeeBookAtom_Body;
|
||||
}
|
||||
else if ( this->IsBigBook() )
|
||||
{
|
||||
size = ((const morkBigBookAtom*) this)->mBigBookAtom_Size;
|
||||
body = ((const morkBigBookAtom*) this)->mBigBookAtom_Body;
|
||||
}
|
||||
else if ( this->IsFarBook() )
|
||||
{
|
||||
size = ((const morkFarBookAtom*) this)->mFarBookAtom_Size;
|
||||
body = ((const morkFarBookAtom*) this)->mFarBookAtom_Body;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->NonBookAtomTypeError(ev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const mork_u1* end = body + size;
|
||||
while ( body < end )
|
||||
{
|
||||
c = *body++;
|
||||
outHash <<= 4;
|
||||
outHash += c;
|
||||
mork_u4 top = outHash & 0xF0000000L; // top four bits
|
||||
if ( top ) // any of high four bits equal to one?
|
||||
{
|
||||
outHash ^= (top >> 24); // fold down high bits
|
||||
outHash ^= top; // zero top four bits
|
||||
}
|
||||
}
|
||||
|
||||
return outHash;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkBookAtom::EqualFormAndBody(morkEnv* ev, const morkBookAtom* inAtom) const
|
||||
{
|
||||
mork_bool outEqual = morkBool_kFalse;
|
||||
|
||||
const mork_u1* body = 0; // body of inAtom bytes to compare
|
||||
mork_size size; // the number of inAtom bytes to compare
|
||||
mork_cscode form; // nominal charset for ioAtom
|
||||
|
||||
if ( inAtom->IsWeeBook() )
|
||||
{
|
||||
size = inAtom->mAtom_Size;
|
||||
body = ((const morkWeeBookAtom*) inAtom)->mWeeBookAtom_Body;
|
||||
form = 0;
|
||||
}
|
||||
else if ( inAtom->IsBigBook() )
|
||||
{
|
||||
size = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Size;
|
||||
body = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Body;
|
||||
form = ((const morkBigBookAtom*) inAtom)->mBigBookAtom_Form;
|
||||
}
|
||||
else if ( inAtom->IsFarBook() )
|
||||
{
|
||||
size = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Size;
|
||||
body = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Body;
|
||||
form = ((const morkFarBookAtom*) inAtom)->mFarBookAtom_Form;
|
||||
}
|
||||
else
|
||||
{
|
||||
inAtom->NonBookAtomTypeError(ev);
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
const mork_u1* thisBody = 0; // body of bytes in this to compare
|
||||
mork_size thisSize; // the number of bytes in this to compare
|
||||
mork_cscode thisForm; // nominal charset for this atom
|
||||
|
||||
if ( this->IsWeeBook() )
|
||||
{
|
||||
thisSize = mAtom_Size;
|
||||
thisBody = ((const morkWeeBookAtom*) this)->mWeeBookAtom_Body;
|
||||
thisForm = 0;
|
||||
}
|
||||
else if ( this->IsBigBook() )
|
||||
{
|
||||
thisSize = ((const morkBigBookAtom*) this)->mBigBookAtom_Size;
|
||||
thisBody = ((const morkBigBookAtom*) this)->mBigBookAtom_Body;
|
||||
thisForm = ((const morkBigBookAtom*) this)->mBigBookAtom_Form;
|
||||
}
|
||||
else if ( this->IsFarBook() )
|
||||
{
|
||||
thisSize = ((const morkFarBookAtom*) this)->mFarBookAtom_Size;
|
||||
thisBody = ((const morkFarBookAtom*) this)->mFarBookAtom_Body;
|
||||
thisForm = ((const morkFarBookAtom*) this)->mFarBookAtom_Form;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->NonBookAtomTypeError(ev);
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
// if atoms are empty, form is irrelevant
|
||||
if ( body && thisBody && size == thisSize && (!size || form == thisForm ))
|
||||
outEqual = (MORK_MEMCMP(body, thisBody, size) == 0);
|
||||
|
||||
return outEqual;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
morkBookAtom::CutBookAtomFromSpace(morkEnv* ev)
|
||||
{
|
||||
morkAtomSpace* space = mBookAtom_Space;
|
||||
if ( space )
|
||||
{
|
||||
mBookAtom_Space = 0;
|
||||
space->mAtomSpace_AtomBodies.CutAtom(ev, this);
|
||||
space->mAtomSpace_AtomAids.CutAtom(ev, this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkWeeBookAtom::morkWeeBookAtom(mork_aid inAid)
|
||||
{
|
||||
mAtom_Kind = morkAtom_kKindWeeBook;
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
mAtom_Size = 0;
|
||||
|
||||
mBookAtom_Space = 0;
|
||||
mBookAtom_Id = inAid;
|
||||
|
||||
mWeeBookAtom_Body[ 0 ] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
morkWeeBookAtom::InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
morkAtomSpace* ioSpace, mork_aid inAid)
|
||||
{
|
||||
mAtom_Kind = 0;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
if ( ioSpace )
|
||||
{
|
||||
if ( inAid )
|
||||
{
|
||||
if ( inBuf.mBuf_Fill <= morkAtom_kMaxByteSize )
|
||||
{
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindWeeBook;
|
||||
mBookAtom_Space = ioSpace;
|
||||
mBookAtom_Id = inAid;
|
||||
mork_size size = inBuf.mBuf_Fill;
|
||||
mAtom_Size = (mork_u1) size;
|
||||
if ( size && inBuf.mBuf_Body )
|
||||
MORK_MEMCPY(mWeeBookAtom_Body, inBuf.mBuf_Body, size);
|
||||
|
||||
mWeeBookAtom_Body[ size ] = 0;
|
||||
}
|
||||
else
|
||||
this->AtomSizeOverflowError(ev);
|
||||
}
|
||||
else
|
||||
this->ZeroAidError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void
|
||||
morkBigBookAtom::InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
|
||||
{
|
||||
mAtom_Kind = 0;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
if ( ioSpace )
|
||||
{
|
||||
if ( inAid )
|
||||
{
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindBigBook;
|
||||
mAtom_Size = 0;
|
||||
mBookAtom_Space = ioSpace;
|
||||
mBookAtom_Id = inAid;
|
||||
mBigBookAtom_Form = inForm;
|
||||
mork_size size = inBuf.mBuf_Fill;
|
||||
mBigBookAtom_Size = size;
|
||||
if ( size && inBuf.mBuf_Body )
|
||||
MORK_MEMCPY(mBigBookAtom_Body, inBuf.mBuf_Body, size);
|
||||
|
||||
mBigBookAtom_Body[ size ] = 0;
|
||||
}
|
||||
else
|
||||
this->ZeroAidError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkFarBookAtom::InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
|
||||
{
|
||||
mAtom_Kind = 0;
|
||||
mAtom_Change = morkChange_kNil;
|
||||
if ( ioSpace )
|
||||
{
|
||||
if ( inAid )
|
||||
{
|
||||
mAtom_CellUses = 0;
|
||||
mAtom_Kind = morkAtom_kKindFarBook;
|
||||
mAtom_Size = 0;
|
||||
mBookAtom_Space = ioSpace;
|
||||
mBookAtom_Id = inAid;
|
||||
mFarBookAtom_Form = inForm;
|
||||
mFarBookAtom_Size = inBuf.mBuf_Fill;
|
||||
mFarBookAtom_Body = (mork_u1*) inBuf.mBuf_Body;
|
||||
}
|
||||
else
|
||||
this->ZeroAidError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#define _MORKATOM_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
#define morkAtom_kMaxByteSize 255 /* max for 8-bit integer */
|
||||
#define morkAtom_kForeverCellUses 0x0FF /* max for 8-bit integer */
|
||||
#define morkAtom_kMaxCellUses 0x07F /* max for 7-bit integer */
|
||||
|
||||
#define morkAtom_kKindWeeAnon 'a' /* means morkWeeAnonAtom subclass */
|
||||
#define morkAtom_kKindBigAnon 'A' /* means morkBigAnonAtom subclass */
|
||||
#define morkAtom_kKindWeeBook 'b' /* means morkWeeBookAtom subclass */
|
||||
#define morkAtom_kKindBigBook 'B' /* means morkBigBookAtom subclass */
|
||||
#define morkAtom_kKindFarBook 'f' /* means morkFarBookAtom subclass */
|
||||
#define morkAtom_kKindRowOid 'r' /* means morkOidAtom subclass */
|
||||
#define morkAtom_kKindTableOid 't' /* means morkOidAtom subclass */
|
||||
|
||||
/*| Atom: .
|
||||
|*/
|
||||
class morkAtom { //
|
||||
|
||||
public:
|
||||
|
||||
mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
mork_change mAtom_Change; // how has this atom been changed?
|
||||
mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
|
||||
|
||||
public:
|
||||
morkAtom(mork_aid inAid, mork_u1 inKind);
|
||||
|
||||
mork_bool IsWeeAnon() const { return mAtom_Kind == morkAtom_kKindWeeAnon; }
|
||||
mork_bool IsBigAnon() const { return mAtom_Kind == morkAtom_kKindBigAnon; }
|
||||
mork_bool IsWeeBook() const { return mAtom_Kind == morkAtom_kKindWeeBook; }
|
||||
mork_bool IsBigBook() const { return mAtom_Kind == morkAtom_kKindBigBook; }
|
||||
mork_bool IsFarBook() const { return mAtom_Kind == morkAtom_kKindFarBook; }
|
||||
mork_bool IsRowOid() const { return mAtom_Kind == morkAtom_kKindRowOid; }
|
||||
mork_bool IsTableOid() const { return mAtom_Kind == morkAtom_kKindTableOid; }
|
||||
|
||||
mork_bool IsBook() const { return this->IsWeeBook() || this->IsBigBook(); }
|
||||
|
||||
public: // clean vs dirty
|
||||
|
||||
void SetAtomClean() { mAtom_Change = morkChange_kNil; }
|
||||
void SetAtomDirty() { mAtom_Change = morkChange_kAdd; }
|
||||
|
||||
mork_bool IsAtomClean() const { return mAtom_Change == morkChange_kNil; }
|
||||
mork_bool IsAtomDirty() const { return mAtom_Change == morkChange_kAdd; }
|
||||
|
||||
public: // atom space scope if IsBook() is true, or else zero:
|
||||
|
||||
mork_scope GetBookAtomSpaceScope(morkEnv* ev) const;
|
||||
// zero or book's space's scope
|
||||
|
||||
mork_aid GetBookAtomAid() const;
|
||||
// zero or book atom's ID
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkAtom() { }
|
||||
|
||||
public: // one-byte refcounting, freezing at maximum
|
||||
void MakeCellUseForever(morkEnv* ev);
|
||||
mork_u1 AddCellUse(morkEnv* ev);
|
||||
mork_u1 CutCellUse(morkEnv* ev);
|
||||
|
||||
mork_bool IsCellUseForever() const
|
||||
{ return mAtom_CellUses == morkAtom_kForeverCellUses; }
|
||||
|
||||
private: // warnings
|
||||
|
||||
static void CellUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
public: // errors
|
||||
|
||||
static void BadAtomKindError(morkEnv* ev);
|
||||
static void ZeroAidError(morkEnv* ev);
|
||||
static void AtomSizeOverflowError(morkEnv* ev);
|
||||
|
||||
public: // yarns
|
||||
|
||||
mork_bool AsBuf(morkBuf& outBuf) const;
|
||||
mork_bool AliasYarn(mdbYarn* outYarn) const;
|
||||
mork_bool GetYarn(mdbYarn* outYarn) const;
|
||||
|
||||
private: // copying is not allowed
|
||||
morkAtom(const morkAtom& other);
|
||||
morkAtom& operator=(const morkAtom& other);
|
||||
};
|
||||
|
||||
/*| OidAtom: an atom that references a row or table by identity.
|
||||
|*/
|
||||
class morkOidAtom : public morkAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
|
||||
|
||||
public:
|
||||
mdbOid mOidAtom_Oid; // identity of referenced object
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkOidAtom() { }
|
||||
void InitRowOidAtom(morkEnv* ev, const mdbOid& inOid);
|
||||
void InitTableOidAtom(morkEnv* ev, const mdbOid& inOid);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkOidAtom(const morkOidAtom& other);
|
||||
morkOidAtom& operator=(const morkOidAtom& other);
|
||||
};
|
||||
|
||||
/*| WeeAnonAtom: an atom whose content immediately follows morkAtom slots
|
||||
**| in an inline fashion, so that morkWeeAnonAtom contains both leading
|
||||
**| atom slots and then the content bytes without further overhead. Note
|
||||
**| that charset encoding is not indicated, so zero is implied for Latin1.
|
||||
**| (Non-Latin1 content must be stored in a morkBigAnonAtom with a charset.)
|
||||
**|
|
||||
**|| An anon (anonymous) atom has no identity, with no associated bookkeeping
|
||||
**| for lookup needed for sharing like a book atom.
|
||||
**|
|
||||
**|| A wee anon atom is immediate but not shared with any other users of this
|
||||
**| atom, so no bookkeeping for sharing is needed. This means the atom has
|
||||
**| no ID, because the atom has no identity other than this immediate content,
|
||||
**| and no hash table is needed to look up this particular atom. This also
|
||||
**| applies to the larger format morkBigAnonAtom, which has more slots.
|
||||
|*/
|
||||
class morkWeeAnonAtom : public morkAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
|
||||
|
||||
public:
|
||||
mork_u1 mWeeAnonAtom_Body[ 1 ]; // 1st byte of immediate content vector
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkWeeAnonAtom() { }
|
||||
void InitWeeAnonAtom(morkEnv* ev, const morkBuf& inBuf);
|
||||
|
||||
// allow extra trailing byte for a null byte:
|
||||
static mork_size SizeForFill(mork_fill inFill)
|
||||
{ return sizeof(morkWeeAnonAtom) + inFill; }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkWeeAnonAtom(const morkWeeAnonAtom& other);
|
||||
morkWeeAnonAtom& operator=(const morkWeeAnonAtom& other);
|
||||
};
|
||||
|
||||
/*| BigAnonAtom: another immediate atom that cannot be encoded as the smaller
|
||||
**| morkWeeAnonAtom format because either the size is too great, and/or the
|
||||
**| charset is not the default zero for Latin1 and must be explicitly noted.
|
||||
**|
|
||||
**|| An anon (anonymous) atom has no identity, with no associated bookkeeping
|
||||
**| for lookup needed for sharing like a book atom.
|
||||
|*/
|
||||
class morkBigAnonAtom : public morkAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
|
||||
|
||||
public:
|
||||
mork_cscode mBigAnonAtom_Form; // charset format encoding
|
||||
mork_size mBigAnonAtom_Size; // size of content vector
|
||||
mork_u1 mBigAnonAtom_Body[ 1 ]; // 1st byte of immed content vector
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkBigAnonAtom() { }
|
||||
void InitBigAnonAtom(morkEnv* ev, const morkBuf& inBuf, mork_cscode inForm);
|
||||
|
||||
// allow extra trailing byte for a null byte:
|
||||
static mork_size SizeForFill(mork_fill inFill)
|
||||
{ return sizeof(morkBigAnonAtom) + inFill; }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBigAnonAtom(const morkBigAnonAtom& other);
|
||||
morkBigAnonAtom& operator=(const morkBigAnonAtom& other);
|
||||
};
|
||||
|
||||
#define morkBookAtom_kMaxBodySize 1024 /* if larger, cannot be shared */
|
||||
|
||||
/*| BookAtom: the common subportion of wee book atoms and big book atoms that
|
||||
**| includes the atom ID and the pointer to the space referencing this atom
|
||||
**| through a hash table.
|
||||
|*/
|
||||
class morkBookAtom : public morkAtom { //
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
|
||||
|
||||
public:
|
||||
morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is atom scope
|
||||
mork_aid mBookAtom_Id; // identity token for this shared atom
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkBookAtom() { }
|
||||
|
||||
static void NonBookAtomTypeError(morkEnv* ev);
|
||||
|
||||
public: // Hash() and Equal() for atom ID maps are same for all subclasses:
|
||||
|
||||
mork_u4 HashAid() const { return mBookAtom_Id; }
|
||||
mork_bool EqualAid(const morkBookAtom* inAtom) const
|
||||
{ return ( mBookAtom_Id == inAtom->mBookAtom_Id); }
|
||||
|
||||
public: // Hash() and Equal() for atom body maps know about subclasses:
|
||||
|
||||
// YOU CANNOT SUBCLASS morkBookAtom WITHOUT FIXING Hash and Equal METHODS:
|
||||
|
||||
mork_u4 HashFormAndBody(morkEnv* ev) const;
|
||||
mork_bool EqualFormAndBody(morkEnv* ev, const morkBookAtom* inAtom) const;
|
||||
|
||||
public: // separation from containing space
|
||||
|
||||
void CutBookAtomFromSpace(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBookAtom(const morkBookAtom& other);
|
||||
morkBookAtom& operator=(const morkBookAtom& other);
|
||||
};
|
||||
|
||||
/*| FarBookAtom: this alternative format for book atoms was introduced
|
||||
**| in May 2000 in order to support finding atoms in hash tables without
|
||||
**| first copying the strings from original parsing buffers into a new
|
||||
**| atom format. This was consuming too much time. However, we can
|
||||
**| use morkFarBookAtom to stage a hash table query, as long as we then
|
||||
**| fix HashFormAndBody() and EqualFormAndBody() to use morkFarBookAtom
|
||||
**| correctly.
|
||||
**|
|
||||
**|| Note we do NOT intend that instances of morkFarBookAtom will ever
|
||||
**| be installed in hash tables, because this is not space efficient.
|
||||
**| We only expect to create temp instances for table lookups.
|
||||
|*/
|
||||
class morkFarBookAtom : public morkBookAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
|
||||
|
||||
// morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
|
||||
// mork_aid mBookAtom_Id; // identity token for this shared atom
|
||||
|
||||
public:
|
||||
mork_cscode mFarBookAtom_Form; // charset format encoding
|
||||
mork_size mFarBookAtom_Size; // size of content vector
|
||||
mork_u1* mFarBookAtom_Body; // bytes are elsewere, out of line
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkFarBookAtom() { }
|
||||
void InitFarBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkFarBookAtom(const morkFarBookAtom& other);
|
||||
morkFarBookAtom& operator=(const morkFarBookAtom& other);
|
||||
};
|
||||
|
||||
/*| WeeBookAtom: .
|
||||
|*/
|
||||
class morkWeeBookAtom : public morkBookAtom { //
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // only for atoms smaller than 256 bytes
|
||||
|
||||
// morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
|
||||
// mork_aid mBookAtom_Id; // identity token for this shared atom
|
||||
|
||||
public:
|
||||
mork_u1 mWeeBookAtom_Body[ 1 ]; // 1st byte of immed content vector
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkWeeBookAtom() { }
|
||||
morkWeeBookAtom(mork_aid inAid);
|
||||
|
||||
void InitWeeBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
morkAtomSpace* ioSpace, mork_aid inAid);
|
||||
|
||||
// allow extra trailing byte for a null byte:
|
||||
static mork_size SizeForFill(mork_fill inFill)
|
||||
{ return sizeof(morkWeeBookAtom) + inFill; }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkWeeBookAtom(const morkWeeBookAtom& other);
|
||||
morkWeeBookAtom& operator=(const morkWeeBookAtom& other);
|
||||
};
|
||||
|
||||
/*| BigBookAtom: .
|
||||
|*/
|
||||
class morkBigBookAtom : public morkBookAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
|
||||
|
||||
// morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
|
||||
// mork_aid mBookAtom_Id; // identity token for this shared atom
|
||||
|
||||
public:
|
||||
mork_cscode mBigBookAtom_Form; // charset format encoding
|
||||
mork_size mBigBookAtom_Size; // size of content vector
|
||||
mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkBigBookAtom() { }
|
||||
void InitBigBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid);
|
||||
|
||||
// allow extra trailing byte for a null byte:
|
||||
static mork_size SizeForFill(mork_fill inFill)
|
||||
{ return sizeof(morkBigBookAtom) + inFill; }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBigBookAtom(const morkBigBookAtom& other);
|
||||
morkBigBookAtom& operator=(const morkBigBookAtom& other);
|
||||
};
|
||||
|
||||
/*| MaxBookAtom: .
|
||||
|*/
|
||||
class morkMaxBookAtom : public morkBigBookAtom { //
|
||||
|
||||
// mork_u1 mAtom_Kind; // identifies a specific atom subclass
|
||||
// mork_u1 mAtom_CellUses; // number of persistent uses in a cell
|
||||
// mork_change mAtom_Change; // how has this atom been changed?
|
||||
// mork_u1 mAtom_Size; // NOT USED IN "BIG" format atoms
|
||||
|
||||
// morkAtomSpace* mBookAtom_Space; // mBookAtom_Space->SpaceScope() is scope
|
||||
// mork_aid mBookAtom_Id; // identity token for this shared atom
|
||||
|
||||
// mork_cscode mBigBookAtom_Form; // charset format encoding
|
||||
// mork_size mBigBookAtom_Size; // size of content vector
|
||||
// mork_u1 mBigBookAtom_Body[ 1 ]; // 1st byte of immed content vector
|
||||
|
||||
public:
|
||||
mork_u1 mMaxBookAtom_Body[ morkBookAtom_kMaxBodySize + 3 ]; // max bytes
|
||||
|
||||
public: // empty construction does nothing
|
||||
morkMaxBookAtom() { }
|
||||
void InitMaxBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid)
|
||||
{ this->InitBigBookAtom(ev, inBuf, inForm, ioSpace, inAid); }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkMaxBookAtom(const morkMaxBookAtom& other);
|
||||
morkMaxBookAtom& operator=(const morkMaxBookAtom& other);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKATOM_ */
|
||||
|
|
@ -0,0 +1,469 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMMAP_
|
||||
#include "morkAtomMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#include "morkAtom.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#include "morkIntMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkAtomAidMap::CloseMorkNode(morkEnv* ev) // CloseAtomAidMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseAtomAidMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkAtomAidMap::~morkAtomAidMap() // assert CloseAtomAidMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkAtomAidMap::morkAtomAidMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
: morkProbeMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
|
||||
ioSlotHeap, morkAtomAidMap_kStartSlotCount,
|
||||
/*inZeroIsClearKey*/ morkBool_kTrue)
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
: morkMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
|
||||
morkAtomAidMap_kStartSlotCount, ioSlotHeap,
|
||||
/*inHoldChanges*/ morkBool_kFalse)
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomAidMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkAtomAidMap::CloseAtomAidMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->CloseProbeMap(ev);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->CloseMap(ev);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
|
||||
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
morkAtomAidMap::MapTest(morkEnv* ev, const void* inMapKey,
|
||||
const void* inAppKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
|
||||
if ( key )
|
||||
{
|
||||
mork_bool hit = key->EqualAid(*(const morkBookAtom**) inAppKey);
|
||||
return ( hit ) ? morkTest_kHit : morkTest_kMiss;
|
||||
}
|
||||
else
|
||||
return morkTest_kVoid;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
morkAtomAidMap::MapHash(morkEnv* ev, const void* inAppKey) const
|
||||
{
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inAppKey;
|
||||
if ( key )
|
||||
return key->HashAid();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkAtomAidMap::ProbeMapHashMapKey(morkEnv* ev,
|
||||
const void* inMapKey) const
|
||||
{
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
|
||||
if ( key )
|
||||
return key->HashAid();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool //
|
||||
morkAtomAidMap::Equal(morkEnv* ev, const void* inKeyA,
|
||||
const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBookAtom**) inKeyA)->EqualAid(
|
||||
*(const morkBookAtom**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 //
|
||||
morkAtomAidMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBookAtom**) inKey)->HashAid();
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
|
||||
mork_bool
|
||||
morkAtomAidMap::AddAtom(morkEnv* ev, morkBookAtom* ioAtom)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->MapAtPut(ev, &ioAtom, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Put(ev, &ioAtom, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomAidMap::CutAtom(morkEnv* ev, const morkBookAtom* inAtom)
|
||||
{
|
||||
morkBookAtom* oldKey = 0;
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
MORK_USED_1(inAtom);
|
||||
morkProbeMap::ProbeMapCutError(ev);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Cut(ev, &inAtom, &oldKey, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomAidMap::GetAtom(morkEnv* ev, const morkBookAtom* inAtom)
|
||||
{
|
||||
morkBookAtom* key = 0; // old val in the map
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->MapAt(ev, &inAtom, &key, /*val*/ (void*) 0);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Get(ev, &inAtom, &key, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomAidMap::GetAid(morkEnv* ev, mork_aid inAid)
|
||||
{
|
||||
morkWeeBookAtom weeAtom(inAid);
|
||||
morkBookAtom* key = &weeAtom; // we need a pointer
|
||||
morkBookAtom* oldKey = 0; // old key in the map
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->MapAt(ev, &key, &oldKey, /*val*/ (void*) 0);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Get(ev, &key, &oldKey, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkAtomBodyMap::CloseMorkNode(morkEnv* ev) // CloseAtomBodyMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseAtomBodyMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkAtomBodyMap::~morkAtomBodyMap() // assert CloseAtomBodyMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkAtomBodyMap::morkAtomBodyMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
: morkProbeMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
|
||||
ioSlotHeap, morkAtomBodyMap_kStartSlotCount,
|
||||
/*inZeroIsClearKey*/ morkBool_kTrue)
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
: morkMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBookAtom*), /*inValSize*/ 0,
|
||||
morkAtomBodyMap_kStartSlotCount, ioSlotHeap,
|
||||
/*inHoldChanges*/ morkBool_kFalse)
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomBodyMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkAtomBodyMap::CloseAtomBodyMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->CloseProbeMap(ev);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->CloseMap(ev);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
|
||||
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
morkAtomBodyMap::MapTest(morkEnv* ev, const void* inMapKey,
|
||||
const void* inAppKey) const
|
||||
{
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
|
||||
if ( key )
|
||||
{
|
||||
return ( key->EqualFormAndBody(ev, *(const morkBookAtom**) inAppKey) ) ?
|
||||
morkTest_kHit : morkTest_kMiss;
|
||||
}
|
||||
else
|
||||
return morkTest_kVoid;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
morkAtomBodyMap::MapHash(morkEnv* ev, const void* inAppKey) const
|
||||
{
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inAppKey;
|
||||
if ( key )
|
||||
return key->HashFormAndBody(ev);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkAtomBodyMap::ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const
|
||||
{
|
||||
const morkBookAtom* key = *(const morkBookAtom**) inMapKey;
|
||||
if ( key )
|
||||
return key->HashFormAndBody(ev);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool //
|
||||
morkAtomBodyMap::Equal(morkEnv* ev, const void* inKeyA,
|
||||
const void* inKeyB) const
|
||||
{
|
||||
return (*(const morkBookAtom**) inKeyA)->EqualFormAndBody(ev,
|
||||
*(const morkBookAtom**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 //
|
||||
morkAtomBodyMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
return (*(const morkBookAtom**) inKey)->HashFormAndBody(ev);
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
|
||||
mork_bool
|
||||
morkAtomBodyMap::AddAtom(morkEnv* ev, morkBookAtom* ioAtom)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->MapAtPut(ev, &ioAtom, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Put(ev, &ioAtom, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomBodyMap::CutAtom(morkEnv* ev, const morkBookAtom* inAtom)
|
||||
{
|
||||
morkBookAtom* oldKey = 0;
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
MORK_USED_1(inAtom);
|
||||
morkProbeMap::ProbeMapCutError(ev);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Cut(ev, &inAtom, &oldKey, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomBodyMap::GetAtom(morkEnv* ev, const morkBookAtom* inAtom)
|
||||
{
|
||||
morkBookAtom* key = 0; // old val in the map
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
this->MapAt(ev, &inAtom, &key, /*val*/ (void*) 0);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
this->Get(ev, &inAtom, &key, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
morkAtomRowMap::~morkAtomRowMap()
|
||||
{
|
||||
}
|
||||
|
||||
// I changed to sizeof(mork_ip) from sizeof(mork_aid) to fix a crash on
|
||||
// 64 bit machines. I am not sure it was the right way to fix the problem,
|
||||
// but it does stop the crash. Perhaps we should be using the
|
||||
// morkPointerMap instead?
|
||||
morkAtomRowMap::morkAtomRowMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_column inIndexColumn)
|
||||
: morkIntMap(ev, inUsage, sizeof(mork_ip), ioHeap, ioSlotHeap,
|
||||
/*inHoldChanges*/ morkBool_kFalse)
|
||||
, mAtomRowMap_IndexColumn( inIndexColumn )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomRowMap;
|
||||
}
|
||||
|
||||
void morkAtomRowMap::AddRow(morkEnv* ev, morkRow* ioRow)
|
||||
// add ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
|
||||
{
|
||||
mork_aid aid = ioRow->GetCellAtomAid(ev, mAtomRowMap_IndexColumn);
|
||||
if ( aid )
|
||||
this->AddAid(ev, aid, ioRow);
|
||||
}
|
||||
|
||||
void morkAtomRowMap::CutRow(morkEnv* ev, morkRow* ioRow)
|
||||
// cut ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
|
||||
{
|
||||
mork_aid aid = ioRow->GetCellAtomAid(ev, mAtomRowMap_IndexColumn);
|
||||
if ( aid )
|
||||
this->CutAid(ev, aid);
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,397 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKATOMMAP_
|
||||
#define _MORKATOMMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#include "morkProbeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#include "morkIntMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kAtomAidMap /*i*/ 0x6141 /* ascii 'aA' */
|
||||
|
||||
#define morkAtomAidMap_kStartSlotCount 23
|
||||
|
||||
/*| morkAtomAidMap: keys of morkBookAtom organized by atom ID
|
||||
|*/
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
class morkAtomAidMap : public morkProbeMap { // for mapping tokens to maps
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
class morkAtomAidMap : public morkMap { // for mapping tokens to maps
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseAtomAidMap() only if open
|
||||
virtual ~morkAtomAidMap(); // assert that CloseAtomAidMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkAtomAidMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseAtomAidMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsAtomAidMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kAtomAidMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public:
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
|
||||
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
|
||||
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
|
||||
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
// void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
|
||||
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// } ===== end morkProbeMap methods =====
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
// implemented using morkBookAtom::HashAid()
|
||||
|
||||
virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// implemented using morkBookAtom::EqualAid()
|
||||
// } ===== end morkMap poly interface =====
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddAtom(morkEnv* ev, morkBookAtom* ioAtom);
|
||||
// AddAtom() returns ev->Good()
|
||||
|
||||
morkBookAtom* CutAtom(morkEnv* ev, const morkBookAtom* inAtom);
|
||||
// CutAtom() returns the atom removed equal to inAtom, if there was one
|
||||
|
||||
morkBookAtom* GetAtom(morkEnv* ev, const morkBookAtom* inAtom);
|
||||
// GetAtom() returns the atom equal to inAtom, or else nil
|
||||
|
||||
morkBookAtom* GetAid(morkEnv* ev, mork_aid inAid);
|
||||
// GetAid() returns the atom equal to inAid, or else nil
|
||||
|
||||
// note the atoms are owned elsewhere, usuall by morkAtomSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakAtomAidMap(morkAtomAidMap* me,
|
||||
morkEnv* ev, morkAtomAidMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongAtomAidMap(morkAtomAidMap* me,
|
||||
morkEnv* ev, morkAtomAidMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
class morkAtomAidMapIter: public morkProbeMapIter { // typesafe wrapper class
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
class morkAtomAidMapIter: public morkMapIter { // typesafe wrapper class
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
public:
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
|
||||
: morkProbeMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomAidMapIter( ) : morkProbeMapIter() { }
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomAidMapIter( ) : morkMapIter() { }
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
void InitAtomAidMapIter(morkEnv* ev, morkAtomAidMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change* FirstAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->First(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* NextAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->Next(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* HereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->Here(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* CutHereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->CutHere(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kAtomBodyMap /*i*/ 0x6142 /* ascii 'aB' */
|
||||
|
||||
#define morkAtomBodyMap_kStartSlotCount 23
|
||||
|
||||
/*| morkAtomBodyMap: keys of morkBookAtom organized by body bytes
|
||||
|*/
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
class morkAtomBodyMap : public morkProbeMap { // for mapping tokens to maps
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
class morkAtomBodyMap : public morkMap { // for mapping tokens to maps
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseAtomBodyMap() only if open
|
||||
virtual ~morkAtomBodyMap(); // assert CloseAtomBodyMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkAtomBodyMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseAtomBodyMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsAtomBodyMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kAtomBodyMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public:
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
|
||||
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
|
||||
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
|
||||
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
// void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
|
||||
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// } ===== end morkProbeMap methods =====
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
// implemented using morkBookAtom::EqualFormAndBody()
|
||||
|
||||
virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// implemented using morkBookAtom::HashFormAndBody()
|
||||
// } ===== end morkMap poly interface =====
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddAtom(morkEnv* ev, morkBookAtom* ioAtom);
|
||||
// AddAtom() returns ev->Good()
|
||||
|
||||
morkBookAtom* CutAtom(morkEnv* ev, const morkBookAtom* inAtom);
|
||||
// CutAtom() returns the atom removed equal to inAtom, if there was one
|
||||
|
||||
morkBookAtom* GetAtom(morkEnv* ev, const morkBookAtom* inAtom);
|
||||
// GetAtom() returns the atom equal to inAtom, or else nil
|
||||
|
||||
// note the atoms are owned elsewhere, usuall by morkAtomSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakAtomBodyMap(morkAtomBodyMap* me,
|
||||
morkEnv* ev, morkAtomBodyMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongAtomBodyMap(morkAtomBodyMap* me,
|
||||
morkEnv* ev, morkAtomBodyMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
class morkAtomBodyMapIter: public morkProbeMapIter{ // typesafe wrapper class
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
class morkAtomBodyMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
public:
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
|
||||
: morkProbeMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomBodyMapIter( ) : morkProbeMapIter() { }
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomBodyMapIter( ) : morkMapIter() { }
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
void InitAtomBodyMapIter(morkEnv* ev, morkAtomBodyMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change* FirstAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->First(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* NextAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->Next(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* HereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->Here(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* CutHereAtom(morkEnv* ev, morkBookAtom** outAtomPtr)
|
||||
{ return this->CutHere(ev, outAtomPtr, /*val*/ (void*) 0); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kAtomRowMap /*i*/ 0x6152 /* ascii 'aR' */
|
||||
|
||||
/*| morkAtomRowMap: maps morkAtom* -> morkRow*
|
||||
|*/
|
||||
class morkAtomRowMap : public morkIntMap { // for mapping atoms to rows
|
||||
|
||||
public:
|
||||
mork_column mAtomRowMap_IndexColumn; // row column being indexed
|
||||
|
||||
public:
|
||||
|
||||
virtual ~morkAtomRowMap();
|
||||
morkAtomRowMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_column inIndexColumn);
|
||||
|
||||
public: // adding and cutting from morkRow instance candidate
|
||||
|
||||
void AddRow(morkEnv* ev, morkRow* ioRow);
|
||||
// add ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
|
||||
|
||||
void CutRow(morkEnv* ev, morkRow* ioRow);
|
||||
// cut ioRow only if it contains a cell in mAtomRowMap_IndexColumn.
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddAid(morkEnv* ev, mork_aid inAid, morkRow* ioRow)
|
||||
{ return this->AddInt(ev, inAid, ioRow); }
|
||||
// the AddAid() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutAid(morkEnv* ev, mork_aid inAid)
|
||||
{ return this->CutInt(ev, inAid); }
|
||||
// The CutAid() boolean return indicates whether removal happened.
|
||||
|
||||
morkRow* GetAid(morkEnv* ev, mork_aid inAid)
|
||||
{ return (morkRow*) this->GetInt(ev, inAid); }
|
||||
// Note the returned space does NOT have an increase in refcount for this.
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsAtomRowMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kAtomRowMap; }
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakAtomRowMap(morkAtomRowMap* me,
|
||||
morkEnv* ev, morkAtomRowMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongAtomRowMap(morkAtomRowMap* me,
|
||||
morkEnv* ev, morkAtomRowMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
};
|
||||
|
||||
class morkAtomRowMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkAtomRowMapIter(morkEnv* ev, morkAtomRowMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomRowMapIter( ) : morkMapIter() { }
|
||||
void InitAtomRowMapIter(morkEnv* ev, morkAtomRowMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change*
|
||||
FirstAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
|
||||
{ return this->First(ev, outAtom, outRow); }
|
||||
|
||||
mork_change*
|
||||
NextAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
|
||||
{ return this->Next(ev, outAtom, outRow); }
|
||||
|
||||
mork_change*
|
||||
HereAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
|
||||
{ return this->Here(ev, outAtom, outRow); }
|
||||
|
||||
mork_change*
|
||||
CutHereAtomAndRow(morkEnv* ev, morkAtom** outAtom, morkRow** outRow)
|
||||
{ return this->CutHere(ev, outAtom, outRow); }
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKATOMMAP_ */
|
|
@ -0,0 +1,307 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMSPACE_
|
||||
#include "morkAtomSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#include "morkAtom.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkAtomSpace::CloseMorkNode(morkEnv* ev) // CloseAtomSpace() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseAtomSpace(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkAtomSpace::~morkAtomSpace() // assert CloseAtomSpace() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mAtomSpace_HighUnderId==0);
|
||||
MORK_ASSERT(mAtomSpace_HighOverId==0);
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
MORK_ASSERT(mAtomSpace_AtomAids.IsShutNode());
|
||||
MORK_ASSERT(mAtomSpace_AtomBodies.IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkAtomSpace::morkAtomSpace(morkEnv* ev, const morkUsage& inUsage,
|
||||
mork_scope inScope, morkStore* ioStore,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkSpace(ev, inUsage, inScope, ioStore, ioHeap, ioSlotHeap)
|
||||
, mAtomSpace_HighUnderId( morkAtomSpace_kMinUnderId )
|
||||
, mAtomSpace_HighOverId( morkAtomSpace_kMinOverId )
|
||||
, mAtomSpace_AtomAids(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
, mAtomSpace_AtomBodies(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
{
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomSpace;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkAtomSpace::CloseAtomSpace(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mAtomSpace_AtomBodies.CloseMorkNode(ev);
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
this->CutAllAtoms(ev, &store->mStore_Pool);
|
||||
|
||||
mAtomSpace_AtomAids.CloseMorkNode(ev);
|
||||
this->CloseSpace(ev);
|
||||
mAtomSpace_HighUnderId = 0;
|
||||
mAtomSpace_HighOverId = 0;
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkAtomSpace::NonAtomSpaceTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkAtomSpace");
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkAtomSpace::CutAllAtoms(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
#ifdef MORK_ENABLE_ZONE_ARENAS
|
||||
MORK_USED_2(ev, ioPool);
|
||||
return 0;
|
||||
#else /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mAtomSpace_AtomAids.MapFill();
|
||||
morkBookAtom* a = 0; // old key atom in the map
|
||||
|
||||
morkStore* store = mSpace_Store;
|
||||
mork_change* c = 0;
|
||||
morkAtomAidMapIter i(ev, &mAtomSpace_AtomAids);
|
||||
for ( c = i.FirstAtom(ev, &a); c ; c = i.NextAtom(ev, &a) )
|
||||
{
|
||||
if ( a )
|
||||
ioPool->ZapAtom(ev, a, &store->mStore_Zone);
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
// do not cut anything from the map
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
i.CutHereAtom(ev, /*key*/ (morkBookAtom**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
}
|
||||
|
||||
return outSlots;
|
||||
#endif /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
}
|
||||
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomSpace::MakeBookAtomCopyWithAid(morkEnv* ev,
|
||||
const morkFarBookAtom& inAtom, mork_aid inAid)
|
||||
// Make copy of inAtom and put it in both maps, using specified ID.
|
||||
{
|
||||
morkBookAtom* outAtom = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( ev->Good() && store )
|
||||
{
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
outAtom = pool->NewFarBookAtomCopy(ev, inAtom, &store->mStore_Zone);
|
||||
if ( outAtom )
|
||||
{
|
||||
if ( store->mStore_CanDirty )
|
||||
{
|
||||
outAtom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom->mBookAtom_Id = inAid;
|
||||
outAtom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, outAtom);
|
||||
mAtomSpace_AtomBodies.AddAtom(ev, outAtom);
|
||||
if ( this->SpaceScope() == morkAtomSpace_kColumnScope )
|
||||
outAtom->MakeCellUseForever(ev);
|
||||
|
||||
if ( mAtomSpace_HighUnderId <= inAid )
|
||||
mAtomSpace_HighUnderId = inAid + 1;
|
||||
}
|
||||
}
|
||||
return outAtom;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkAtomSpace::MakeBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom)
|
||||
// make copy of inAtom and put it in both maps, using a new ID as needed.
|
||||
{
|
||||
morkBookAtom* outAtom = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( ev->Good() && store )
|
||||
{
|
||||
if ( store->mStore_CanAutoAssignAtomIdentity )
|
||||
{
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
morkBookAtom* atom = pool->NewFarBookAtomCopy(ev, inAtom, &mSpace_Store->mStore_Zone);
|
||||
if ( atom )
|
||||
{
|
||||
mork_aid id = this->MakeNewAtomId(ev, atom);
|
||||
if ( id )
|
||||
{
|
||||
if ( store->mStore_CanDirty )
|
||||
{
|
||||
atom->SetAtomDirty();
|
||||
if ( this->IsAtomSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
}
|
||||
|
||||
outAtom = atom;
|
||||
atom->mBookAtom_Space = this;
|
||||
mAtomSpace_AtomAids.AddAtom(ev, atom);
|
||||
mAtomSpace_AtomBodies.AddAtom(ev, atom);
|
||||
if ( this->SpaceScope() == morkAtomSpace_kColumnScope )
|
||||
outAtom->MakeCellUseForever(ev);
|
||||
}
|
||||
else
|
||||
pool->ZapAtom(ev, atom, &mSpace_Store->mStore_Zone);
|
||||
}
|
||||
}
|
||||
else
|
||||
mSpace_Store->CannotAutoAssignAtomIdentityError(ev);
|
||||
}
|
||||
return outAtom;
|
||||
}
|
||||
|
||||
|
||||
mork_aid
|
||||
morkAtomSpace::MakeNewAtomId(morkEnv* ev, morkBookAtom* ioAtom)
|
||||
{
|
||||
mork_aid outAid = 0;
|
||||
mork_tid id = mAtomSpace_HighUnderId;
|
||||
mork_num count = 8; // try up to eight times
|
||||
|
||||
while ( !outAid && count ) // still trying to find an unused table ID?
|
||||
{
|
||||
--count;
|
||||
ioAtom->mBookAtom_Id = id;
|
||||
if ( !mAtomSpace_AtomAids.GetAtom(ev, ioAtom) )
|
||||
outAid = id;
|
||||
else
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
mAtomSpace_HighUnderId = id + 1;
|
||||
return outAid;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkAtomSpaceMap::~morkAtomSpaceMap()
|
||||
{
|
||||
}
|
||||
|
||||
morkAtomSpaceMap::morkAtomSpaceMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kAtomSpaceMap;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKATOMSPACE_
|
||||
#define _MORKATOMSPACE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMMAP_
|
||||
#include "morkAtomMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| kMinUnderId: the smallest ID we auto-assign to the 'under' namespace
|
||||
**| reserved for tokens expected to occur very frequently, such as the names
|
||||
**| of columns. We reserve single byte ids in the ASCII range to correspond
|
||||
**| one-to-one to those tokens consisting single ASCII characters (so that
|
||||
**| this assignment is always known and constant). So we start at 0x80, and
|
||||
**| then reserve the upper half of two hex digit ids and all the three hex
|
||||
**| digit IDs for the 'under' namespace for common tokens.
|
||||
|*/
|
||||
#define morkAtomSpace_kMinUnderId 0x80 /* low 7 bits mean byte tokens */
|
||||
|
||||
#define morkAtomSpace_kMaxSevenBitAid 0x7F /* low seven bit integer ID */
|
||||
|
||||
/*| kMinOverId: the smallest ID we auto-assign to the 'over' namespace that
|
||||
**| might include very large numbers of tokens that are used infrequently,
|
||||
**| so that we care less whether the shortest hex representation is used.
|
||||
**| So we start all IDs for 'over' category tokens at a value range that
|
||||
**| needs at least four hex digits, so we can reserve three hex digits and
|
||||
**| shorter for more commonly occuring tokens in the 'under' category.
|
||||
|*/
|
||||
#define morkAtomSpace_kMinOverId 0x1000 /* using at least four hex bytes */
|
||||
|
||||
#define morkDerived_kAtomSpace /*i*/ 0x6153 /* ascii 'aS' */
|
||||
|
||||
#define morkAtomSpace_kColumnScope ((mork_scope) 'c') /* column scope is forever */
|
||||
|
||||
/*| morkAtomSpace:
|
||||
|*/
|
||||
class morkAtomSpace : public morkSpace { //
|
||||
|
||||
// public: // slots inherited from morkSpace (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkStore* mSpace_Store; // weak ref to containing store
|
||||
|
||||
// mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
|
||||
// mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
|
||||
// mork_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
mork_aid mAtomSpace_HighUnderId; // high ID in 'under' range
|
||||
mork_aid mAtomSpace_HighOverId; // high ID in 'over' range
|
||||
|
||||
morkAtomAidMap mAtomSpace_AtomAids; // all atoms in space by ID
|
||||
morkAtomBodyMap mAtomSpace_AtomBodies; // all atoms in space by body
|
||||
|
||||
public: // more specific dirty methods for atom space:
|
||||
void SetAtomSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetAtomSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsAtomSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsAtomSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseAtomSpace() only if open
|
||||
virtual ~morkAtomSpace(); // assert that CloseAtomSpace() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkAtomSpace(morkEnv* ev, const morkUsage& inUsage, mork_scope inScope,
|
||||
morkStore* ioStore, nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseAtomSpace(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsAtomSpace() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kAtomSpace; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
void NonAtomSpaceTypeError(morkEnv* ev);
|
||||
|
||||
public: // setup
|
||||
|
||||
mork_bool MarkAllAtomSpaceContentDirty(morkEnv* ev);
|
||||
// MarkAllAtomSpaceContentDirty() visits every space object and marks
|
||||
// them dirty, including every table, row, cell, and atom. The return
|
||||
// equals ev->Good(), to show whether any error happened. This method is
|
||||
// intended for use in the beginning of a "compress commit" which writes
|
||||
// all store content, whether dirty or not. We dirty everything first so
|
||||
// that later iterations over content can mark things clean as they are
|
||||
// written, and organize the process of serialization so that objects are
|
||||
// written only at need (because of being dirty).
|
||||
|
||||
public: // other space methods
|
||||
|
||||
// void ReserveColumnAidCount(mork_count inCount)
|
||||
// {
|
||||
// mAtomSpace_HighUnderId = morkAtomSpace_kMinUnderId + inCount;
|
||||
// mAtomSpace_HighOverId = morkAtomSpace_kMinOverId + inCount;
|
||||
// }
|
||||
|
||||
mork_num CutAllAtoms(morkEnv* ev, morkPool* ioPool);
|
||||
// CutAllAtoms() puts all the atoms back in the pool.
|
||||
|
||||
morkBookAtom* MakeBookAtomCopyWithAid(morkEnv* ev,
|
||||
const morkFarBookAtom& inAtom, mork_aid inAid);
|
||||
// Make copy of inAtom and put it in both maps, using specified ID.
|
||||
|
||||
morkBookAtom* MakeBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom);
|
||||
// Make copy of inAtom and put it in both maps, using a new ID as needed.
|
||||
|
||||
mork_aid MakeNewAtomId(morkEnv* ev, morkBookAtom* ioAtom);
|
||||
// generate an unused atom id.
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakAtomSpace(morkAtomSpace* me,
|
||||
morkEnv* ev, morkAtomSpace** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongAtomSpace(morkAtomSpace* me,
|
||||
morkEnv* ev, morkAtomSpace** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kAtomSpaceMap /*i*/ 0x615A /* ascii 'aZ' */
|
||||
|
||||
/*| morkAtomSpaceMap: maps mork_scope -> morkAtomSpace
|
||||
|*/
|
||||
class morkAtomSpaceMap : public morkNodeMap { // for mapping tokens to tables
|
||||
|
||||
public:
|
||||
|
||||
virtual ~morkAtomSpaceMap();
|
||||
morkAtomSpaceMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddAtomSpace(morkEnv* ev, morkAtomSpace* ioAtomSpace)
|
||||
{ return this->AddNode(ev, ioAtomSpace->SpaceScope(), ioAtomSpace); }
|
||||
// the AddAtomSpace() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutAtomSpace(morkEnv* ev, mork_scope inScope)
|
||||
{ return this->CutNode(ev, inScope); }
|
||||
// The CutAtomSpace() boolean return indicates whether removal happened.
|
||||
|
||||
morkAtomSpace* GetAtomSpace(morkEnv* ev, mork_scope inScope)
|
||||
{ return (morkAtomSpace*) this->GetNode(ev, inScope); }
|
||||
// Note the returned space does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllAtomSpaces(morkEnv* ev)
|
||||
{ return this->CutAllNodes(ev); }
|
||||
// CutAllAtomSpaces() releases all the referenced table values.
|
||||
};
|
||||
|
||||
class morkAtomSpaceMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkAtomSpaceMapIter(morkEnv* ev, morkAtomSpaceMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkAtomSpaceMapIter( ) : morkMapIter() { }
|
||||
void InitAtomSpaceMapIter(morkEnv* ev, morkAtomSpaceMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change*
|
||||
FirstAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
|
||||
{ return this->First(ev, outScope, outAtomSpace); }
|
||||
|
||||
mork_change*
|
||||
NextAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
|
||||
{ return this->Next(ev, outScope, outAtomSpace); }
|
||||
|
||||
mork_change*
|
||||
HereAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
|
||||
{ return this->Here(ev, outScope, outAtomSpace); }
|
||||
|
||||
mork_change*
|
||||
CutHereAtomSpace(morkEnv* ev, mork_scope* outScope, morkAtomSpace** outAtomSpace)
|
||||
{ return this->CutHere(ev, outScope, outAtomSpace); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKATOMSPACE_ */
|
||||
|
|
@ -0,0 +1,472 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#include "morkBead.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBead::CloseMorkNode(morkEnv* ev) // CloseBead() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBead(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBead::~morkBead() // assert CloseBead() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mBead_Color==0 || mNode_Usage == morkUsage_kStack );
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(mork_color inBeadColor)
|
||||
: morkNode( morkUsage_kStack )
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor)
|
||||
: morkNode( inUsage, ioHeap )
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBead::morkBead(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, mork_color inBeadColor)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
, mBead_Color( inBeadColor )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBead;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBead::CloseBead(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( !this->IsShutNode() )
|
||||
{
|
||||
mBead_Color = 0;
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBeadMap::CloseMorkNode(morkEnv* ev) // CloseBeadMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBeadMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBeadMap::~morkBeadMap() // assert CloseBeadMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkBeadMap::morkBeadMap(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkMap(ev, inUsage, ioHeap, sizeof(morkBead*), /*inValSize*/ 0,
|
||||
/*slotCount*/ 11, ioSlotHeap, /*holdChanges*/ morkBool_kFalse)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBeadMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBeadMap::CloseBeadMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CutAllBeads(ev);
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_bool
|
||||
morkBeadMap::AddBead(morkEnv* ev, morkBead* ioBead)
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
{
|
||||
if ( ioBead && ev->Good() )
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
|
||||
mork_bool put = this->Put(ev, &ioBead, /*val*/ (void*) 0,
|
||||
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
if ( put ) // replaced an existing key?
|
||||
{
|
||||
if ( oldBead != ioBead ) // new bead was not already in table?
|
||||
ioBead->AddStrongRef(ev); // now there's another ref
|
||||
|
||||
if ( oldBead && oldBead != ioBead ) // need to release old node?
|
||||
oldBead->CutStrongRef(ev);
|
||||
}
|
||||
else
|
||||
ioBead->AddStrongRef(ev); // another ref if not already in table
|
||||
}
|
||||
else if ( !ioBead )
|
||||
ev->NilPointerError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkBeadMap::CutBead(morkEnv* ev, mork_color inColor)
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
mork_bool outCutNode = this->Cut(ev, &key,
|
||||
/*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
if ( oldBead )
|
||||
oldBead->CutStrongRef(ev);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return outCutNode;
|
||||
}
|
||||
|
||||
morkBead*
|
||||
morkBeadMap::GetBead(morkEnv* ev, mork_color inColor)
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
this->Get(ev, &key, /*key*/ &oldBead, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return oldBead;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkBeadMap::CutAllBeads(morkEnv* ev)
|
||||
// CutAllBeads() releases all the referenced beads.
|
||||
{
|
||||
mork_num outSlots = mMap_Slots;
|
||||
|
||||
morkBeadMapIter i(ev, this);
|
||||
morkBead* b = i.FirstBead(ev);
|
||||
|
||||
while ( b )
|
||||
{
|
||||
b->CutStrongRef(ev);
|
||||
i.CutHereBead(ev);
|
||||
b = i.NextBead(ev);
|
||||
}
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool
|
||||
morkBeadMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBead**) inKeyA)->BeadEqual(
|
||||
*(const morkBead**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkBeadMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkBead**) inKey)->BeadHash();
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkBead* morkBeadMapIter::FirstBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->First(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
morkBead* morkBeadMapIter::NextBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->Next(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
morkBead* morkBeadMapIter::HereBead(morkEnv* ev)
|
||||
{
|
||||
morkBead* bead = 0;
|
||||
this->Here(ev, &bead, /*val*/ (void*) 0);
|
||||
return bead;
|
||||
}
|
||||
|
||||
void morkBeadMapIter::CutHereBead(morkEnv* ev)
|
||||
{
|
||||
this->CutHere(ev, /*key*/ (void*) 0, /*val*/ (void*) 0);
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkBeadProbeMap::CloseMorkNode(morkEnv* ev) // CloseBeadProbeMap() if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseBeadProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkBeadProbeMap::~morkBeadProbeMap() // assert CloseBeadProbeMap() earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkBeadProbeMap::morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkProbeMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkBead*), /*inValSize*/ 0,
|
||||
ioSlotHeap, /*startSlotCount*/ 11,
|
||||
/*inZeroIsClearKey*/ morkBool_kTrue)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kBeadProbeMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkBeadProbeMap::CloseBeadProbeMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CutAllBeads(ev);
|
||||
this->CloseProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
morkBeadProbeMap::MapTest(morkEnv* ev, const void* inMapKey,
|
||||
const void* inAppKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
const morkBead* key = *(const morkBead**) inMapKey;
|
||||
if ( key )
|
||||
{
|
||||
mork_bool hit = key->BeadEqual(*(const morkBead**) inAppKey);
|
||||
return ( hit ) ? morkTest_kHit : morkTest_kMiss;
|
||||
}
|
||||
else
|
||||
return morkTest_kVoid;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
morkBeadProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
|
||||
{
|
||||
const morkBead* key = *(const morkBead**) inAppKey;
|
||||
if ( key )
|
||||
return key->BeadHash();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkBeadProbeMap::ProbeMapHashMapKey(morkEnv* ev,
|
||||
const void* inMapKey) const
|
||||
{
|
||||
const morkBead* key = *(const morkBead**) inMapKey;
|
||||
if ( key )
|
||||
return key->BeadHash();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkBeadProbeMap::AddBead(morkEnv* ev, morkBead* ioBead)
|
||||
{
|
||||
if ( ioBead && ev->Good() )
|
||||
{
|
||||
morkBead* bead = 0; // old key in the map
|
||||
|
||||
mork_bool put = this->MapAtPut(ev, &ioBead, /*val*/ (void*) 0,
|
||||
/*key*/ &bead, /*val*/ (void*) 0);
|
||||
|
||||
if ( put ) // replaced an existing key?
|
||||
{
|
||||
if ( bead != ioBead ) // new bead was not already in table?
|
||||
ioBead->AddStrongRef(ev); // now there's another ref
|
||||
|
||||
if ( bead && bead != ioBead ) // need to release old node?
|
||||
bead->CutStrongRef(ev);
|
||||
}
|
||||
else
|
||||
ioBead->AddStrongRef(ev); // now there's another ref
|
||||
}
|
||||
else if ( !ioBead )
|
||||
ev->NilPointerError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkBead*
|
||||
morkBeadProbeMap::GetBead(morkEnv* ev, mork_color inColor)
|
||||
{
|
||||
morkBead* oldBead = 0; // old key in the map
|
||||
morkBead bead(inColor);
|
||||
morkBead* key = &bead;
|
||||
|
||||
this->MapAt(ev, &key, &oldBead, /*val*/ (void*) 0);
|
||||
|
||||
bead.CloseBead(ev);
|
||||
return oldBead;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkBeadProbeMap::CutAllBeads(morkEnv* ev)
|
||||
// CutAllBeads() releases all the referenced bead values.
|
||||
{
|
||||
mork_num outSlots = sMap_Slots;
|
||||
|
||||
morkBeadProbeMapIter i(ev, this);
|
||||
morkBead* b = i.FirstBead(ev);
|
||||
|
||||
while ( b )
|
||||
{
|
||||
b->CutStrongRef(ev);
|
||||
b = i.NextBead(ev);
|
||||
}
|
||||
this->MapCutAll(ev);
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#define _MORKBEAD_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#include "morkProbeMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBead /*i*/ 0x426F /* ascii 'Bo' */
|
||||
|
||||
/*| morkBead: subclass of morkNode that adds knowledge of db suite factory
|
||||
**| and containing port to those objects that are exposed as instances of
|
||||
**| nsIMdbBead in the public interface.
|
||||
|*/
|
||||
class morkBead : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
mork_color mBead_Color; // ID for this bead
|
||||
|
||||
public: // Hash() and Equal() for bead maps are same for all subclasses:
|
||||
|
||||
mork_u4 BeadHash() const { return (mork_u4) mBead_Color; }
|
||||
mork_bool BeadEqual(const morkBead* inBead) const
|
||||
{ return ( mBead_Color == inBead->mBead_Color); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBead() only if open
|
||||
virtual ~morkBead(); // assert that CloseBead() executed earlier
|
||||
|
||||
public: // special case for stack construction for map usage:
|
||||
morkBead(mork_color inBeadColor); // stack-based bead instance
|
||||
|
||||
protected: // special case for morkObject:
|
||||
morkBead(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor);
|
||||
|
||||
public: // morkEnv construction & destruction
|
||||
morkBead(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor);
|
||||
void CloseBead(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBead(const morkBead& other);
|
||||
morkBead& operator=(const morkBead& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBead() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBead; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// void NewNilHandleError(morkEnv* ev); // mBead_Handle is nil
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakBead(morkBead* me,
|
||||
morkEnv* ev, morkBead** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongBead(morkBead* me,
|
||||
morkEnv* ev, morkBead** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBeadMap /*i*/ 0x744D /* ascii 'bM' */
|
||||
|
||||
/*| morkBeadMap: maps bead -> bead (key only using mBead_Color)
|
||||
|*/
|
||||
class morkBeadMap : public morkMap {
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadMap() only if open
|
||||
virtual ~morkBeadMap(); // assert that CloseBeadMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkBeadMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseBeadMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBeadMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBeadMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
public:
|
||||
virtual mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
|
||||
virtual mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutBead(morkEnv* ev, mork_color inColor);
|
||||
// The CutBead() boolean return indicates whether removal happened.
|
||||
|
||||
morkBead* GetBead(morkEnv* ev, mork_color inColor);
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllBeads(morkEnv* ev);
|
||||
// CutAllBeads() releases all the referenced beads.
|
||||
};
|
||||
|
||||
class morkBeadMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkBeadMapIter( ) : morkMapIter() { }
|
||||
void InitBeadMapIter(morkEnv* ev, morkBeadMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
morkBead* FirstBead(morkEnv* ev);
|
||||
morkBead* NextBead(morkEnv* ev);
|
||||
morkBead* HereBead(morkEnv* ev);
|
||||
void CutHereBead(morkEnv* ev);
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kBeadProbeMap /*i*/ 0x6D74 /* ascii 'mb' */
|
||||
|
||||
/*| morkBeadProbeMap: maps bead -> bead (key only using mBead_Color)
|
||||
|*/
|
||||
class morkBeadProbeMap : public morkProbeMap {
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBeadProbeMap() only if open
|
||||
virtual ~morkBeadProbeMap(); // assert that CloseBeadProbeMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkBeadProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseBeadProbeMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBeadProbeMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBeadProbeMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
public:
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
|
||||
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
|
||||
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
|
||||
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
// void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
|
||||
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// } ===== end morkProbeMap methods =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddBead(morkEnv* ev, morkBead* ioBead);
|
||||
// the AddBead() boolean return equals ev->Good().
|
||||
|
||||
morkBead* GetBead(morkEnv* ev, mork_color inColor);
|
||||
// Note the returned bead does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllBeads(morkEnv* ev);
|
||||
// CutAllBeads() releases all the referenced bead values.
|
||||
};
|
||||
|
||||
class morkBeadProbeMapIter: public morkProbeMapIter { // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
|
||||
: morkProbeMapIter(ev, ioMap) { }
|
||||
|
||||
morkBeadProbeMapIter( ) : morkProbeMapIter() { }
|
||||
void InitBeadProbeMapIter(morkEnv* ev, morkBeadProbeMap* ioMap)
|
||||
{ this->InitProbeMapIter(ev, ioMap); }
|
||||
|
||||
morkBead* FirstBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterFirstKey(ev); }
|
||||
|
||||
morkBead* NextBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterNextKey(ev); }
|
||||
|
||||
morkBead* HereBead(morkEnv* ev)
|
||||
{ return (morkBead*) this->IterHereKey(ev); }
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKBEAD_ */
|
|
@ -0,0 +1,142 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*static*/ void
|
||||
morkBuf::NilBufBodyError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mBuf_Body");
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*static*/ void
|
||||
morkBlob::BlobFillOverSizeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mBuf_Fill > mBlob_Size");
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
mork_bool
|
||||
morkBlob::GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap, mork_size inNewSize)
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
if ( !mBuf_Body ) // no body? implies zero sized?
|
||||
mBlob_Size = 0;
|
||||
|
||||
if ( mBuf_Fill > mBlob_Size ) // fill more than size?
|
||||
{
|
||||
ev->NewWarning("mBuf_Fill > mBlob_Size");
|
||||
mBuf_Fill = mBlob_Size;
|
||||
}
|
||||
|
||||
if ( inNewSize > mBlob_Size ) // need to allocate larger blob?
|
||||
{
|
||||
mork_u1* body = 0;
|
||||
ioHeap->Alloc(ev->AsMdbEnv(), inNewSize, (void**) &body);
|
||||
if ( body && ev->Good() )
|
||||
{
|
||||
void* oldBody = mBuf_Body;
|
||||
if ( mBlob_Size ) // any old content to transfer?
|
||||
MORK_MEMCPY(body, oldBody, mBlob_Size);
|
||||
|
||||
mBlob_Size = inNewSize; // install new size
|
||||
mBuf_Body = body; // install new body
|
||||
|
||||
if ( oldBody ) // need to free old buffer body?
|
||||
ioHeap->Free(ev->AsMdbEnv(), oldBody);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
if ( ev->Good() && mBlob_Size < inNewSize )
|
||||
ev->NewError("mBlob_Size < inNewSize");
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
morkCoil::morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
mBuf_Body = 0;
|
||||
mBuf_Fill = 0;
|
||||
mBlob_Size = 0;
|
||||
mText_Form = 0;
|
||||
mCoil_Heap = ioHeap;
|
||||
if ( !ioHeap )
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void
|
||||
morkCoil::CloseCoil(morkEnv* ev)
|
||||
{
|
||||
void* body = mBuf_Body;
|
||||
nsIMdbHeap* heap = mCoil_Heap;
|
||||
|
||||
mBuf_Body = 0;
|
||||
mCoil_Heap = 0;
|
||||
|
||||
if ( body && heap )
|
||||
{
|
||||
heap->Free(ev->AsMdbEnv(), body);
|
||||
}
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,173 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#define _MORKBLOB_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| Buf: the minimum needed to describe location and content length.
|
||||
**| This is typically only enough to read from this buffer, since
|
||||
**| one cannot write effectively without knowing the size of a buf.
|
||||
|*/
|
||||
class morkBuf { // subset of nsIMdbYarn slots
|
||||
public:
|
||||
void* mBuf_Body; // space for holding any binary content
|
||||
mork_fill mBuf_Fill; // logical content in Buf in bytes
|
||||
|
||||
public:
|
||||
morkBuf() { }
|
||||
morkBuf(const void* ioBuf, mork_fill inFill)
|
||||
: mBuf_Body((void*) ioBuf), mBuf_Fill(inFill) { }
|
||||
|
||||
void ClearBufFill() { mBuf_Fill = 0; }
|
||||
|
||||
static void NilBufBodyError(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBuf(const morkBuf& other);
|
||||
morkBuf& operator=(const morkBuf& other);
|
||||
};
|
||||
|
||||
/*| Blob: a buffer with an associated size, to increase known buf info
|
||||
**| to include max capacity in addition to buf location and content.
|
||||
**| This form factor allows us to allocate a vector of such blobs,
|
||||
**| which can share the same managing heap stored elsewhere, and that
|
||||
**| is why we don't include a pointer to a heap in this blob class.
|
||||
|*/
|
||||
class morkBlob : public morkBuf { // greater subset of nsIMdbYarn slots
|
||||
|
||||
// void* mBuf_Body; // space for holding any binary content
|
||||
// mdb_fill mBuf_Fill; // logical content in Buf in bytes
|
||||
public:
|
||||
mork_size mBlob_Size; // physical size of Buf in bytes
|
||||
|
||||
public:
|
||||
morkBlob() { }
|
||||
morkBlob(const void* ioBuf, mork_fill inFill, mork_size inSize)
|
||||
: morkBuf(ioBuf, inFill), mBlob_Size(inSize) { }
|
||||
|
||||
static void BlobFillOverSizeError(morkEnv* ev);
|
||||
|
||||
public:
|
||||
mork_bool GrowBlob(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
mork_size inNewSize);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBlob(const morkBlob& other);
|
||||
morkBlob& operator=(const morkBlob& other);
|
||||
|
||||
};
|
||||
|
||||
/*| Text: a blob with an associated charset annotation, where the
|
||||
**| charset actually includes the general notion of typing, and not
|
||||
**| just a specification of character set alone; we want to permit
|
||||
**| arbitrary charset annotations for ad hoc binary types as well.
|
||||
**| (We avoid including a nsIMdbHeap pointer in morkText for the same
|
||||
**| reason morkBlob does: we want minimal size vectors of morkText.)
|
||||
|*/
|
||||
class morkText : public morkBlob { // greater subset of nsIMdbYarn slots
|
||||
|
||||
// void* mBuf_Body; // space for holding any binary content
|
||||
// mdb_fill mBuf_Fill; // logical content in Buf in bytes
|
||||
// mdb_size mBlob_Size; // physical size of Buf in bytes
|
||||
|
||||
public:
|
||||
mork_cscode mText_Form; // charset format encoding
|
||||
|
||||
morkText() { }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkText(const morkText& other);
|
||||
morkText& operator=(const morkText& other);
|
||||
};
|
||||
|
||||
/*| Coil: a text with an associated nsIMdbHeap instance that provides
|
||||
**| all memory management for the space pointed to by mBuf_Body. (This
|
||||
**| was the hardest type to give a name in this small class hierarchy,
|
||||
**| because it's hard to characterize self-management of one's space.)
|
||||
**| A coil is a self-contained blob that knows how to grow itself as
|
||||
**| necessary to hold more content when necessary. Coil descends from
|
||||
**| morkText to include the mText_Form slot, even though this won't be
|
||||
**| needed always, because we are not as concerned about the overall
|
||||
**| size of this particular Coil object (if we were concerned about
|
||||
**| the size of an array of Coil instances, we would not bother with
|
||||
**| a separate heap pointer for each of them).
|
||||
**|
|
||||
**|| A coil makes a good medium in which to stream content as a sink,
|
||||
**| so we will have a subclass of morkSink called morkCoil that
|
||||
**| will stream bytes into this self-contained coil object. The name
|
||||
**| of this morkCoil class derives more from this intended usage than
|
||||
**| from anything else. The Mork code to parse db content will use
|
||||
**| coils with associated sinks to accumulate parsed strings.
|
||||
**|
|
||||
**|| Heap: this is the heap used for memory allocation. This instance
|
||||
**| is NOT refcounted, since this coil always assumes the heap is held
|
||||
**| through a reference elsewhere (for example, through the same object
|
||||
**| that contains or holds the coil itself. This lack of refcounting
|
||||
**| is consistent with the fact that morkCoil itself is not refcounted,
|
||||
**| and is not intended for use as a standalone object.
|
||||
|*/
|
||||
class morkCoil : public morkText { // self-managing text blob object
|
||||
|
||||
// void* mBuf_Body; // space for holding any binary content
|
||||
// mdb_fill mBuf_Fill; // logical content in Buf in bytes
|
||||
// mdb_size mBlob_Size; // physical size of Buf in bytes
|
||||
// mdb_cscode mText_Form; // charset format encoding
|
||||
public:
|
||||
nsIMdbHeap* mCoil_Heap; // storage manager for mBuf_Body pointer
|
||||
|
||||
public:
|
||||
morkCoil(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
void CloseCoil(morkEnv* ev);
|
||||
|
||||
mork_bool GrowCoil(morkEnv* ev, mork_size inNewSize)
|
||||
{ return this->GrowBlob(ev, mCoil_Heap, inNewSize); }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkCoil(const morkCoil& other);
|
||||
morkCoil& operator=(const morkCoil& other);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKBLOB_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,335 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKBUILDER_
|
||||
#define _MORKBUILDER_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPARSER_
|
||||
#include "morkParser.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| kCellsVecSize: length of cell vector buffer inside morkBuilder
|
||||
|*/
|
||||
#define morkBuilder_kCellsVecSize 64
|
||||
|
||||
#define morkBuilder_kDefaultBytesPerParseSegment 512 /* plausible to big */
|
||||
|
||||
#define morkDerived_kBuilder /*i*/ 0x4275 /* ascii 'Bu' */
|
||||
|
||||
class morkBuilder /*d*/ : public morkParser {
|
||||
|
||||
// public: // slots inherited from morkParser (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
|
||||
// nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation
|
||||
// morkStream* mParser_Stream; // refcounted input stream
|
||||
|
||||
// mork_u4 mParser_Tag; // must equal morkParser_kTag
|
||||
// mork_count mParser_MoreGranularity; // constructor inBytesPerParseSegment
|
||||
|
||||
// mork_u4 mParser_State; // state where parser should resume
|
||||
|
||||
// after finding ends of group transactions, we can re-seek the start:
|
||||
// mork_pos mParser_GroupContentStartPos; // start of this group
|
||||
|
||||
// mdbOid mParser_TableOid; // table oid if inside a table
|
||||
// mdbOid mParser_RowOid; // row oid if inside a row
|
||||
// mork_gid mParser_GroupId; // group ID if inside a group
|
||||
|
||||
// mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd?
|
||||
// mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd?
|
||||
// mork_bool mParser_InCell; // called OnNewCell but not OnCellEnd?
|
||||
// mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd?
|
||||
|
||||
// morkMid mParser_Mid; // current alias being parsed
|
||||
// note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below:
|
||||
|
||||
// blob coils allocated in mParser_Heap
|
||||
// morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs
|
||||
// morkCoil mParser_ValueCoil; // place to accumulate value blobs
|
||||
// morkCoil mParser_ColumnCoil; // place to accumulate column blobs
|
||||
// morkCoil mParser_StringCoil; // place to accumulate string blobs
|
||||
|
||||
// morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil
|
||||
// morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil
|
||||
// morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil
|
||||
// morkSpool mParser_StringSpool; // writes to mParser_StringCoil
|
||||
|
||||
// yarns allocated in mParser_Heap
|
||||
// morkYarn mParser_MidYarn; // place to receive from MidToYarn()
|
||||
|
||||
// span showing current ongoing file position status:
|
||||
// morkSpan mParser_PortSpan; // span of current db port file
|
||||
|
||||
// various spans denoting nested subspaces inside the file's port span:
|
||||
// morkSpan mParser_GroupSpan; // span of current transaction group
|
||||
// morkSpan mParser_DictSpan;
|
||||
// morkSpan mParser_AliasSpan;
|
||||
// morkSpan mParser_MetaDictSpan;
|
||||
// morkSpan mParser_TableSpan;
|
||||
// morkSpan mParser_MetaTableSpan;
|
||||
// morkSpan mParser_RowSpan;
|
||||
// morkSpan mParser_MetaRowSpan;
|
||||
// morkSpan mParser_CellSpan;
|
||||
// morkSpan mParser_ColumnSpan;
|
||||
// morkSpan mParser_SlotSpan;
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkBuilder members
|
||||
|
||||
// weak refs that do not prevent closure of referenced nodes:
|
||||
morkStore* mBuilder_Store; // weak ref to builder's store
|
||||
|
||||
// strong refs that do indeed prevent closure of referenced nodes:
|
||||
morkTable* mBuilder_Table; // current table being built (or nil)
|
||||
morkRow* mBuilder_Row; // current row being built (or nil)
|
||||
morkCell* mBuilder_Cell; // current cell within CellsVec (or nil)
|
||||
|
||||
morkRowSpace* mBuilder_RowSpace; // space for mBuilder_CellRowScope
|
||||
morkAtomSpace* mBuilder_AtomSpace; // space for mBuilder_CellAtomScope
|
||||
|
||||
morkAtomSpace* mBuilder_OidAtomSpace; // ground atom space for oids
|
||||
morkAtomSpace* mBuilder_ScopeAtomSpace; // ground atom space for scopes
|
||||
|
||||
// scoped object ids for current objects under construction:
|
||||
mdbOid mBuilder_TableOid; // full oid for current table
|
||||
mdbOid mBuilder_RowOid; // full oid for current row
|
||||
|
||||
// tokens that become set as the result of meta cells in port rows:
|
||||
mork_cscode mBuilder_PortForm; // default port charset format
|
||||
mork_scope mBuilder_PortRowScope; // port row scope
|
||||
mork_scope mBuilder_PortAtomScope; // port atom scope
|
||||
|
||||
// tokens that become set as the result of meta cells in meta tables:
|
||||
mork_cscode mBuilder_TableForm; // default table charset format
|
||||
mork_scope mBuilder_TableRowScope; // table row scope
|
||||
mork_scope mBuilder_TableAtomScope; // table atom scope
|
||||
mork_kind mBuilder_TableKind; // table kind
|
||||
|
||||
mork_token mBuilder_TableStatus; // dummy: priority/unique/verbose
|
||||
|
||||
mork_priority mBuilder_TablePriority; // table priority
|
||||
mork_bool mBuilder_TableIsUnique; // table uniqueness
|
||||
mork_bool mBuilder_TableIsVerbose; // table verboseness
|
||||
mork_u1 mBuilder_TablePadByte; // for u4 alignment
|
||||
|
||||
// tokens that become set as the result of meta cells in meta rows:
|
||||
mork_cscode mBuilder_RowForm; // default row charset format
|
||||
mork_scope mBuilder_RowRowScope; // row scope per row metainfo
|
||||
mork_scope mBuilder_RowAtomScope; // row atom scope
|
||||
|
||||
// meta tokens currently in force, driven by meta info slots above:
|
||||
mork_cscode mBuilder_CellForm; // cell charset format
|
||||
mork_scope mBuilder_CellAtomScope; // cell atom scope
|
||||
|
||||
mork_cscode mBuilder_DictForm; // dict charset format
|
||||
mork_scope mBuilder_DictAtomScope; // dict atom scope
|
||||
|
||||
mork_token* mBuilder_MetaTokenSlot; // pointer to some slot above
|
||||
|
||||
// If any of these 'cut' bools are true, it means a minus was seen in the
|
||||
// Mork source text to indicate removal of content from some container.
|
||||
// (Note there is no corresponding 'add' bool, since add is the default.)
|
||||
// CutRow implies the current row should be cut from the table.
|
||||
// CutCell implies the current column should be cut from the row.
|
||||
mork_bool mBuilder_DoCutRow; // row with kCut change
|
||||
mork_bool mBuilder_DoCutCell; // cell with kCut change
|
||||
mork_u1 mBuilder_row_pad; // pad to u4 alignment
|
||||
mork_u1 mBuilder_cell_pad; // pad to u4 alignment
|
||||
|
||||
morkCell mBuilder_CellsVec[ morkBuilder_kCellsVecSize + 1 ];
|
||||
mork_fill mBuilder_CellsVecFill; // count used in CellsVec
|
||||
// Note when mBuilder_CellsVecFill equals morkBuilder_kCellsVecSize, and
|
||||
// another cell is added, this means all the cells in the vector above
|
||||
// must be flushed to the current row being built to create more room.
|
||||
|
||||
protected: // protected inlines
|
||||
|
||||
mork_bool CellVectorIsFull() const
|
||||
{ return ( mBuilder_CellsVecFill == morkBuilder_kCellsVecSize ); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseBuilder() only if open
|
||||
virtual ~morkBuilder(); // assert that CloseBuilder() executed earlier
|
||||
|
||||
public: // morkYarn construction & destruction
|
||||
morkBuilder(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
morkStream* ioStream, // the readonly stream for input bytes
|
||||
mdb_count inBytesPerParseSegment, // target for ParseMore()
|
||||
nsIMdbHeap* ioSlotHeap, morkStore* ioStore
|
||||
);
|
||||
|
||||
void CloseBuilder(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkBuilder(const morkBuilder& other);
|
||||
morkBuilder& operator=(const morkBuilder& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsBuilder() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kBuilder; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // errors
|
||||
static void NonBuilderTypeError(morkEnv* ev);
|
||||
static void NilBuilderCellError(morkEnv* ev);
|
||||
static void NilBuilderRowError(morkEnv* ev);
|
||||
static void NilBuilderTableError(morkEnv* ev);
|
||||
static void NonColumnSpaceScopeError(morkEnv* ev);
|
||||
|
||||
void LogGlitch(morkEnv* ev, const morkGlitch& inGlitch,
|
||||
const char* inKind);
|
||||
|
||||
public: // other builder methods
|
||||
|
||||
morkCell* AddBuilderCell(morkEnv* ev,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
|
||||
void FlushBuilderCells(morkEnv* ev);
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // in virtual morkParser methods, data flow subclass to parser
|
||||
|
||||
virtual void MidToYarn(morkEnv* ev,
|
||||
const morkMid& inMid, // typically an alias to concat with strings
|
||||
mdbYarn* outYarn);
|
||||
// The parser might ask that some aliases be turned into yarns, so they
|
||||
// can be concatenated into longer blobs under some circumstances. This
|
||||
// is an alternative to using a long and complex callback for many parts
|
||||
// for a single cell value.
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // out virtual morkParser methods, data flow parser to subclass
|
||||
|
||||
virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace);
|
||||
virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid);
|
||||
virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange);
|
||||
virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_bool inCutAllRows);
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace);
|
||||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev);
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_bool inCutAllCols);
|
||||
virtual void OnRowPos(morkEnv* ev, mork_pos inRowPos);
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace);
|
||||
virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid);
|
||||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev);
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf);
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
||||
virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch);
|
||||
virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat);
|
||||
virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan);
|
||||
|
||||
virtual void OnValue(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkBuf& inBuf);
|
||||
|
||||
virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid);
|
||||
|
||||
virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid);
|
||||
|
||||
virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid);
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkBuilder methods
|
||||
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakBuilder(morkBuilder* me,
|
||||
morkEnv* ev, morkBuilder** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongBuilder(morkBuilder* me,
|
||||
morkEnv* ev, morkBuilder** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKBUILDER_ */
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
void
|
||||
morkCell::SetYarn(morkEnv* ev, const mdbYarn* inYarn, morkStore* ioStore)
|
||||
{
|
||||
morkAtom* atom = ioStore->YarnToAtom(ev, inYarn, PR_TRUE /* create */);
|
||||
if ( atom )
|
||||
this->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::GetYarn(morkEnv* ev, mdbYarn* outYarn) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mCell_Atom->GetYarn(outYarn);
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::AliasYarn(morkEnv* ev, mdbYarn* outYarn) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mCell_Atom->AliasYarn(outYarn);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
morkCell::SetCellClean()
|
||||
{
|
||||
mork_column col = this->GetColumn();
|
||||
this->SetColumnAndChange(col, morkChange_kNil);
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::SetCellDirty()
|
||||
{
|
||||
mork_column col = this->GetColumn();
|
||||
this->SetColumnAndChange(col, morkChange_kAdd);
|
||||
}
|
||||
|
||||
void
|
||||
morkCell::SetAtom(morkEnv* ev, morkAtom* ioAtom, morkPool* ioPool)
|
||||
// SetAtom() "acquires" the new ioAtom if non-nil, by calling AddCellUse()
|
||||
// to increase the refcount, and puts ioAtom into mCell_Atom. If the old
|
||||
// atom in mCell_Atom is non-nil, then it is "released" first by a call to
|
||||
// CutCellUse(), and if the use count then becomes zero, then the old atom
|
||||
// is deallocated by returning it to the pool ioPool. (And this is
|
||||
// why ioPool is a parameter to this method.) Note that ioAtom can be nil
|
||||
// to cause the cell to refer to nothing, and the old atom in mCell_Atom
|
||||
// can also be nil, and all the atom refcounting is handled correctly.
|
||||
//
|
||||
// Note that if ioAtom was just created, it typically has a zero use count
|
||||
// before calling SetAtom(). But use count is one higher after SetAtom().
|
||||
{
|
||||
morkAtom* oldAtom = mCell_Atom;
|
||||
if ( oldAtom != ioAtom ) // ioAtom is not already installed in this cell?
|
||||
{
|
||||
if ( oldAtom )
|
||||
{
|
||||
mCell_Atom = 0;
|
||||
if ( oldAtom->CutCellUse(ev) == 0 )
|
||||
{
|
||||
// this was zapping atoms still in use - comment out until davidmc
|
||||
// can figure out a better fix.
|
||||
// if ( ioPool )
|
||||
// {
|
||||
// if ( oldAtom->IsBook() )
|
||||
// ((morkBookAtom*) oldAtom)->CutBookAtomFromSpace(ev);
|
||||
|
||||
// ioPool->ZapAtom(ev, oldAtom);
|
||||
// }
|
||||
// else
|
||||
// ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
if ( ioAtom )
|
||||
ioAtom->AddCellUse(ev);
|
||||
|
||||
mCell_Atom = ioAtom;
|
||||
}
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,121 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#define _MORKCELL_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDelta_kShift 8 /* 8 bit shift */
|
||||
#define morkDelta_kChangeMask 0x0FF /* low 8 bit mask */
|
||||
#define morkDelta_kColumnMask (~ (mork_column) morkDelta_kChangeMask)
|
||||
#define morkDelta_Init(self,cl,ch) ((self) = ((cl)<<morkDelta_kShift) | (ch))
|
||||
#define morkDelta_Change(self) ((mork_change) ((self) & morkDelta_kChangeMask))
|
||||
#define morkDelta_Column(self) ((self) >> morkDelta_kShift)
|
||||
|
||||
class morkCell { // minimal cell format
|
||||
|
||||
public:
|
||||
mork_delta mCell_Delta; // encoding of both column and change
|
||||
morkAtom* mCell_Atom; // content in this cell
|
||||
|
||||
public:
|
||||
morkCell() : mCell_Delta( 0 ), mCell_Atom( 0 ) { }
|
||||
|
||||
morkCell(const morkCell& c)
|
||||
: mCell_Delta( c.mCell_Delta ), mCell_Atom( c.mCell_Atom ) { }
|
||||
|
||||
// note if ioAtom is non-nil, caller needs to call ioAtom->AddCellUse():
|
||||
morkCell(mork_column inCol, mork_change inChange, morkAtom* ioAtom)
|
||||
{
|
||||
morkDelta_Init(mCell_Delta, inCol,inChange);
|
||||
mCell_Atom = ioAtom;
|
||||
}
|
||||
|
||||
// note if ioAtom is non-nil, caller needs to call ioAtom->AddCellUse():
|
||||
void Init(mork_column inCol, mork_change inChange, morkAtom* ioAtom)
|
||||
{
|
||||
morkDelta_Init(mCell_Delta,inCol,inChange);
|
||||
mCell_Atom = ioAtom;
|
||||
}
|
||||
|
||||
mork_column GetColumn() const { return morkDelta_Column(mCell_Delta); }
|
||||
mork_change GetChange() const { return morkDelta_Change(mCell_Delta); }
|
||||
|
||||
mork_bool IsCellClean() const { return GetChange() == morkChange_kNil; }
|
||||
mork_bool IsCellDirty() const { return GetChange() != morkChange_kNil; }
|
||||
|
||||
void SetCellClean(); // set change to kNil
|
||||
void SetCellDirty(); // set change to kAdd
|
||||
|
||||
void SetCellColumnDirty(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kAdd); }
|
||||
|
||||
void SetCellColumnClean(mork_column inCol)
|
||||
{ this->SetColumnAndChange(inCol, morkChange_kNil); }
|
||||
|
||||
void SetColumnAndChange(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mCell_Delta, inCol, inChange); }
|
||||
|
||||
morkAtom* GetAtom() { return mCell_Atom; }
|
||||
|
||||
void SetAtom(morkEnv* ev, morkAtom* ioAtom, morkPool* ioPool);
|
||||
// SetAtom() "acquires" the new ioAtom if non-nil, by calling AddCellUse()
|
||||
// to increase the refcount, and puts ioAtom into mCell_Atom. If the old
|
||||
// atom in mCell_Atom is non-nil, then it is "released" first by a call to
|
||||
// CutCellUse(), and if the use count then becomes zero, then the old atom
|
||||
// is deallocated by returning it to the pool ioPool. (And this is
|
||||
// why ioPool is a parameter to this method.) Note that ioAtom can be nil
|
||||
// to cause the cell to refer to nothing, and the old atom in mCell_Atom
|
||||
// can also be nil, and all the atom refcounting is handled correctly.
|
||||
//
|
||||
// Note that if ioAtom was just created, it typically has a zero use count
|
||||
// before calling SetAtom(). But use count is one higher after SetAtom().
|
||||
|
||||
void SetYarn(morkEnv* ev, const mdbYarn* inYarn, morkStore* ioStore);
|
||||
|
||||
void AliasYarn(morkEnv* ev, mdbYarn* outYarn) const;
|
||||
void GetYarn(morkEnv* ev, mdbYarn* outYarn) const;
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKCELL_ */
|
|
@ -0,0 +1,567 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELLOBJECT_
|
||||
#include "morkCellObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#include "morkRowObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkCellObject::CloseMorkNode(morkEnv* ev) // CloseCellObject() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseCellObject(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkCellObject::~morkCellObject() // assert CloseCellObject() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
MORK_ASSERT(mCellObject_Row==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkCellObject::morkCellObject(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkRow* ioRow, morkCell* ioCell,
|
||||
mork_column inCol, mork_pos inPos)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mCellObject_RowObject( 0 )
|
||||
, mCellObject_Row( 0 )
|
||||
, mCellObject_Cell( 0 )
|
||||
, mCellObject_Col( inCol )
|
||||
, mCellObject_RowSeed( 0 )
|
||||
, mCellObject_Pos( (mork_u2) inPos )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioRow && ioCell )
|
||||
{
|
||||
if ( ioRow->IsRow() )
|
||||
{
|
||||
morkStore* store = ioRow->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
morkRowObject* rowObj = ioRow->AcquireRowObject(ev, store);
|
||||
if ( rowObj )
|
||||
{
|
||||
mCellObject_Row = ioRow;
|
||||
mCellObject_Cell = ioCell;
|
||||
mCellObject_RowSeed = ioRow->mRow_Seed;
|
||||
|
||||
// morkRowObject::SlotStrongRowObject(rowObj, ev,
|
||||
// &mCellObject_RowObject);
|
||||
|
||||
mCellObject_RowObject = rowObj; // assume control of strong ref
|
||||
}
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kCellObject;
|
||||
}
|
||||
}
|
||||
else
|
||||
ioRow->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkCellObject, morkObject, nsIMdbCell)
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkCellObject::CloseCellObject(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
NS_RELEASE(mCellObject_RowObject);
|
||||
mCellObject_Row = 0;
|
||||
mCellObject_Cell = 0;
|
||||
mCellObject_RowSeed = 0;
|
||||
this->CloseObject(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_bool
|
||||
morkCellObject::ResyncWithRow(morkEnv* ev)
|
||||
{
|
||||
morkRow* row = mCellObject_Row;
|
||||
mork_pos pos = 0;
|
||||
morkCell* cell = row->GetCell(ev, mCellObject_Col, &pos);
|
||||
if ( cell )
|
||||
{
|
||||
mCellObject_Pos = (mork_u2) pos;
|
||||
mCellObject_Cell = cell;
|
||||
mCellObject_RowSeed = row->mRow_Seed;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCellObject_Cell = 0;
|
||||
this->MissingRowColumnError(ev);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkAtom*
|
||||
morkCellObject::GetCellAtom(morkEnv* ev) const
|
||||
{
|
||||
morkCell* cell = mCellObject_Cell;
|
||||
if ( cell )
|
||||
return cell->GetAtom();
|
||||
else
|
||||
this->NilCellError(ev);
|
||||
|
||||
return (morkAtom*) 0;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::WrongRowObjectRowError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mCellObject_Row != mCellObject_RowObject->mRowObject_Row");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::NilRowError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mCellObject_Row");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::NilRowObjectError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mCellObject_RowObject");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::NilCellError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mCellObject_Cell");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::NonCellObjectTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkCellObject");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkCellObject::MissingRowColumnError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mCellObject_Col not in mCellObject_Row");
|
||||
}
|
||||
|
||||
nsIMdbCell*
|
||||
morkCellObject::AcquireCellHandle(morkEnv* ev)
|
||||
{
|
||||
nsIMdbCell* outCell = this;
|
||||
NS_ADDREF(outCell);
|
||||
return outCell;
|
||||
}
|
||||
|
||||
|
||||
morkEnv*
|
||||
morkCellObject::CanUseCell(nsIMdbEnv* mev, mork_bool inMutable,
|
||||
mdb_err* outErr, morkCell** outCell)
|
||||
{
|
||||
morkEnv* outEnv = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( IsCellObject() )
|
||||
{
|
||||
if ( IsMutable() || !inMutable )
|
||||
{
|
||||
morkRowObject* rowObj = mCellObject_RowObject;
|
||||
if ( rowObj )
|
||||
{
|
||||
morkRow* row = mCellObject_Row;
|
||||
if ( row )
|
||||
{
|
||||
if ( rowObj->mRowObject_Row == row )
|
||||
{
|
||||
mork_u2 oldSeed = mCellObject_RowSeed;
|
||||
if ( row->mRow_Seed == oldSeed || ResyncWithRow(ev) )
|
||||
{
|
||||
cell = mCellObject_Cell;
|
||||
if ( cell )
|
||||
{
|
||||
outEnv = ev;
|
||||
}
|
||||
else
|
||||
NilCellError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
WrongRowObjectRowError(ev);
|
||||
}
|
||||
else
|
||||
NilRowError(ev);
|
||||
}
|
||||
else
|
||||
NilRowObjectError(ev);
|
||||
}
|
||||
else
|
||||
NonMutableNodeError(ev);
|
||||
}
|
||||
else
|
||||
NonCellObjectTypeError(ev);
|
||||
}
|
||||
*outErr = ev->AsErr();
|
||||
MORK_ASSERT(outEnv);
|
||||
*outCell = cell;
|
||||
|
||||
return outEnv;
|
||||
}
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHODIMP morkCellObject::SetBlob(nsIMdbEnv* /* mev */,
|
||||
nsIMdbBlob* /* ioBlob */)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
} // reads inBlob slots
|
||||
|
||||
// when inBlob is in the same suite, this might be fastest cell-to-cell
|
||||
|
||||
NS_IMETHODIMP morkCellObject::ClearBlob( // make empty (so content has zero length)
|
||||
nsIMdbEnv* /* mev */)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
// clearing a yarn is like SetYarn() with empty yarn instance content
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetBlobFill(nsIMdbEnv* mev,
|
||||
mdb_fill* outFill)
|
||||
// Same value that would be put into mYarn_Fill, if one called GetYarn()
|
||||
// with a yarn instance that had mYarn_Buf==nil and mYarn_Size==0.
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
} // size of blob
|
||||
|
||||
NS_IMETHODIMP morkCellObject::SetYarn(nsIMdbEnv* mev,
|
||||
const mdbYarn* inYarn)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkRow* row = mCellObject_Row;
|
||||
if ( row )
|
||||
{
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
cell->SetYarn(ev, inYarn, store);
|
||||
if ( row->IsRowClean() && store->mStore_CanDirty )
|
||||
row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
} // reads from yarn slots
|
||||
// make this text object contain content from the yarn's buffer
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetYarn(nsIMdbEnv* mev,
|
||||
mdbYarn* outYarn)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkAtom* atom = cell->GetAtom();
|
||||
atom->GetYarn(outYarn);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
} // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
|
||||
NS_IMETHODIMP morkCellObject::AliasYarn(nsIMdbEnv* mev,
|
||||
mdbYarn* outYarn)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkAtom* atom = cell->GetAtom();
|
||||
atom->AliasYarn(outYarn);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
} // writes ALL yarn slots
|
||||
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// } ===== end nsIMdbBlob methods =====
|
||||
|
||||
// { ===== begin nsIMdbCell methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHODIMP morkCellObject::SetColumn(nsIMdbEnv* mev, mdb_column inColumn)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetColumn(nsIMdbEnv* mev, mdb_column* outColumn)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_column col = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
col = mCellObject_Col;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outColumn )
|
||||
*outColumn = col;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetCellInfo( // all cell metainfo except actual content
|
||||
nsIMdbEnv* mev,
|
||||
mdb_column* outColumn, // the column in the containing row
|
||||
mdb_fill* outBlobFill, // the size of text content in bytes
|
||||
mdbOid* outChildOid, // oid of possible row or table child
|
||||
mdb_bool* outIsRowChild) // nonzero if child, and a row child
|
||||
// Checking all cell metainfo is a good way to avoid forcing a large cell
|
||||
// in to memory when you don't actually want to use the content.
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetRow(nsIMdbEnv* mev, // parent row for this cell
|
||||
nsIMdbRow** acqRow)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbRow* outRow = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
outRow = mCellObject_RowObject->AcquireRowHandle(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqRow )
|
||||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetPort(nsIMdbEnv* mev, // port containing cell
|
||||
nsIMdbPort** acqPort)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbPort* outPort = 0;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mCellObject_Row )
|
||||
{
|
||||
morkStore* store = mCellObject_Row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
outPort = store->AcquireStoreHandle(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqPort )
|
||||
*acqPort = outPort;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin children methods -----
|
||||
NS_IMETHODIMP morkCellObject::HasAnyChild( // does cell have a child instead of text?
|
||||
nsIMdbEnv* mev,
|
||||
mdbOid* outOid, // out id of row or table (or unbound if no child)
|
||||
mdb_bool* outIsRow) // nonzero if child is a row (rather than a table)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool isRow = morkBool_kFalse;
|
||||
outOid->mOid_Scope = 0;
|
||||
outOid->mOid_Id = morkId_kMinusOne;
|
||||
morkCell* cell = 0;
|
||||
morkEnv* ev = this->CanUseCell(mev, /*inMutable*/ morkBool_kTrue,
|
||||
&outErr, &cell);
|
||||
if ( ev )
|
||||
{
|
||||
morkAtom* atom = GetCellAtom(ev);
|
||||
if ( atom )
|
||||
{
|
||||
isRow = atom->IsRowOid();
|
||||
if ( isRow || atom->IsTableOid() )
|
||||
*outOid = ((morkOidAtom*) atom)->mOidAtom_Oid;
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outIsRow )
|
||||
*outIsRow = isRow;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetAnyChild( // access table of specific attribute
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow** acqRow, // child row (or null)
|
||||
nsIMdbTable** acqTable) // child table (or null)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP morkCellObject::SetChildRow( // access table of specific attribute
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow* ioRow)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
} // inRow must be bound inside this same db port
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetChildRow( // access row of specific attribute
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow** acqRow) // acquire child row (or nil if no child)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP morkCellObject::SetChildTable( // access table of specific attribute
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbTable* inTable) // table must be bound inside this same db port
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP morkCellObject::GetChildTable( // access table of specific attribute
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbTable** acqTable) // acquire child tabdle (or nil if no chil)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// } ----- end children methods -----
|
||||
|
||||
// } ===== end nsIMdbCell methods =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,205 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKCELLOBJECT_
|
||||
#define _MORKCELLOBJECT_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kCellObject /*i*/ 0x634F /* ascii 'cO' */
|
||||
|
||||
class morkCellObject : public morkObject, public nsIMdbCell { // blob attribute in column scope
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
morkRowObject* mCellObject_RowObject; // strong ref to row's object
|
||||
morkRow* mCellObject_Row; // cell's row if still in row object
|
||||
morkCell* mCellObject_Cell; // cell in row if rowseed matches
|
||||
mork_column mCellObject_Col; // col of cell last living in pos
|
||||
mork_u2 mCellObject_RowSeed; // copy of row's seed
|
||||
mork_u2 mCellObject_Pos; // position of cell in row
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseCellObject() only if open
|
||||
virtual ~morkCellObject(); // assert that CloseCellObject() executed earlier
|
||||
|
||||
public: // morkCellObject construction & destruction
|
||||
morkCellObject(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkRow* ioRow, morkCell* ioCell,
|
||||
mork_column inCol, mork_pos inPos);
|
||||
void CloseCellObject(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
NS_IMETHOD SetBlob(nsIMdbEnv* ev,
|
||||
nsIMdbBlob* ioBlob); // reads inBlob slots
|
||||
// when inBlob is in the same suite, this might be fastest cell-to-cell
|
||||
|
||||
NS_IMETHOD ClearBlob( // make empty (so content has zero length)
|
||||
nsIMdbEnv* ev);
|
||||
// clearing a yarn is like SetYarn() with empty yarn instance content
|
||||
|
||||
NS_IMETHOD GetBlobFill(nsIMdbEnv* ev,
|
||||
mdb_fill* outFill); // size of blob
|
||||
// Same value that would be put into mYarn_Fill, if one called GetYarn()
|
||||
// with a yarn instance that had mYarn_Buf==nil and mYarn_Size==0.
|
||||
|
||||
NS_IMETHOD SetYarn(nsIMdbEnv* ev,
|
||||
const mdbYarn* inYarn); // reads from yarn slots
|
||||
// make this text object contain content from the yarn's buffer
|
||||
|
||||
NS_IMETHOD GetYarn(nsIMdbEnv* ev,
|
||||
mdbYarn* outYarn); // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
|
||||
NS_IMETHOD AliasYarn(nsIMdbEnv* ev,
|
||||
mdbYarn* outYarn); // writes ALL yarn slots
|
||||
NS_IMETHOD SetColumn(nsIMdbEnv* ev, mdb_column inColumn);
|
||||
NS_IMETHOD GetColumn(nsIMdbEnv* ev, mdb_column* outColumn);
|
||||
|
||||
NS_IMETHOD GetCellInfo( // all cell metainfo except actual content
|
||||
nsIMdbEnv* ev,
|
||||
mdb_column* outColumn, // the column in the containing row
|
||||
mdb_fill* outBlobFill, // the size of text content in bytes
|
||||
mdbOid* outChildOid, // oid of possible row or table child
|
||||
mdb_bool* outIsRowChild); // nonzero if child, and a row child
|
||||
|
||||
// Checking all cell metainfo is a good way to avoid forcing a large cell
|
||||
// in to memory when you don't actually want to use the content.
|
||||
|
||||
NS_IMETHOD GetRow(nsIMdbEnv* ev, // parent row for this cell
|
||||
nsIMdbRow** acqRow);
|
||||
NS_IMETHOD GetPort(nsIMdbEnv* ev, // port containing cell
|
||||
nsIMdbPort** acqPort);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin children methods -----
|
||||
NS_IMETHOD HasAnyChild( // does cell have a child instead of text?
|
||||
nsIMdbEnv* ev,
|
||||
mdbOid* outOid, // out id of row or table (or unbound if no child)
|
||||
mdb_bool* outIsRow); // nonzero if child is a row (rather than a table)
|
||||
|
||||
NS_IMETHOD GetAnyChild( // access table of specific attribute
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow** acqRow, // child row (or null)
|
||||
nsIMdbTable** acqTable); // child table (or null)
|
||||
|
||||
|
||||
NS_IMETHOD SetChildRow( // access table of specific attribute
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow); // inRow must be bound inside this same db port
|
||||
|
||||
NS_IMETHOD GetChildRow( // access row of specific attribute
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow** acqRow); // acquire child row (or nil if no child)
|
||||
|
||||
|
||||
NS_IMETHOD SetChildTable( // access table of specific attribute
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbTable* inTable); // table must be bound inside this same db port
|
||||
|
||||
NS_IMETHOD GetChildTable( // access table of specific attribute
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbTable** acqTable); // acquire child table (or nil if no child)
|
||||
// } ----- end children methods -----
|
||||
|
||||
// } ===== end nsIMdbCell methods =====
|
||||
private: // copying is not allowed
|
||||
morkCellObject(const morkCellObject& other);
|
||||
morkCellObject& operator=(const morkCellObject& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsCellObject() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kCellObject; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // other cell node methods
|
||||
|
||||
morkEnv* CanUseCell(nsIMdbEnv* mev, mork_bool inMutable,
|
||||
mdb_err* outErr, morkCell** outCell) ;
|
||||
|
||||
mork_bool ResyncWithRow(morkEnv* ev); // return ev->Good()
|
||||
morkAtom* GetCellAtom(morkEnv* ev) const;
|
||||
|
||||
static void MissingRowColumnError(morkEnv* ev);
|
||||
static void NilRowError(morkEnv* ev);
|
||||
static void NilCellError(morkEnv* ev);
|
||||
static void NilRowObjectError(morkEnv* ev);
|
||||
static void WrongRowObjectRowError(morkEnv* ev);
|
||||
static void NonCellObjectTypeError(morkEnv* ev);
|
||||
|
||||
nsIMdbCell* AcquireCellHandle(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakCellObject(morkCellObject* me,
|
||||
morkEnv* ev, morkCellObject** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongCellObject(morkCellObject* me,
|
||||
morkEnv* ev, morkCellObject** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKCELLOBJECT_ */
|
|
@ -0,0 +1,233 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCH_
|
||||
#include "morkCh.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/* this byte char predicate source file derives from public domain Mithril */
|
||||
/* (that means much of this has a copyright dedicated to the public domain) */
|
||||
|
||||
/*============================================================================*/
|
||||
/* morkCh_Type */
|
||||
|
||||
const mork_flags morkCh_Type[] = /* derives from public domain Mithril table */
|
||||
{
|
||||
0, /* 0x0 */
|
||||
0, /* 0x1 */
|
||||
0, /* 0x2 */
|
||||
0, /* 0x3 */
|
||||
0, /* 0x4 */
|
||||
0, /* 0x5 */
|
||||
0, /* 0x6 */
|
||||
0, /* 0x7 */
|
||||
morkCh_kW, /* 0x8 backspace */
|
||||
morkCh_kW, /* 0x9 tab */
|
||||
morkCh_kW, /* 0xA linefeed */
|
||||
0, /* 0xB */
|
||||
morkCh_kW, /* 0xC page */
|
||||
morkCh_kW, /* 0xD return */
|
||||
0, /* 0xE */
|
||||
0, /* 0xF */
|
||||
0, /* 0x10 */
|
||||
0, /* 0x11 */
|
||||
0, /* 0x12 */
|
||||
0, /* 0x13 */
|
||||
0, /* 0x14 */
|
||||
0, /* 0x15 */
|
||||
0, /* 0x16 */
|
||||
0, /* 0x17 */
|
||||
0, /* 0x18 */
|
||||
0, /* 0x19 */
|
||||
0, /* 0x1A */
|
||||
0, /* 0x1B */
|
||||
0, /* 0x1C */
|
||||
0, /* 0x1D */
|
||||
0, /* 0x1E */
|
||||
0, /* 0x1F */
|
||||
|
||||
morkCh_kV|morkCh_kW, /* 0x20 space */
|
||||
morkCh_kV|morkCh_kM, /* 0x21 ! */
|
||||
morkCh_kV, /* 0x22 " */
|
||||
morkCh_kV, /* 0x23 # */
|
||||
0, /* 0x24 $ cannot be kV because needs escape */
|
||||
morkCh_kV, /* 0x25 % */
|
||||
morkCh_kV, /* 0x26 & */
|
||||
morkCh_kV, /* 0x27 ' */
|
||||
morkCh_kV, /* 0x28 ( */
|
||||
0, /* 0x29 ) cannot be kV because needs escape */
|
||||
morkCh_kV, /* 0x2A * */
|
||||
morkCh_kV|morkCh_kM, /* 0x2B + */
|
||||
morkCh_kV, /* 0x2C , */
|
||||
morkCh_kV|morkCh_kM, /* 0x2D - */
|
||||
morkCh_kV, /* 0x2E . */
|
||||
morkCh_kV, /* 0x2F / */
|
||||
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x30 0 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x31 1 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x32 2 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x33 3 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x34 4 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x35 5 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x36 6 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x37 7 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x38 8 */
|
||||
morkCh_kV|morkCh_kD|morkCh_kX, /* 0x39 9 */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM, /* 0x3A : */
|
||||
morkCh_kV, /* 0x3B ; */
|
||||
morkCh_kV, /* 0x3C < */
|
||||
morkCh_kV, /* 0x3D = */
|
||||
morkCh_kV, /* 0x3E > */
|
||||
morkCh_kV|morkCh_kM, /* 0x3F ? */
|
||||
|
||||
morkCh_kV, /* 0x40 @ */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x41 A */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x42 B */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x43 C */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x44 D */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x45 E */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU|morkCh_kX, /* 0x46 F */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x47 G */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x48 H */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x49 I */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4A J */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4B K */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4C L */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4D M */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4E N */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x4F O */
|
||||
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x50 P */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x51 Q */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x52 R */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x53 S */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x54 T */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x55 U */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x56 V */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x57 W */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x58 X */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x59 Y */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kU, /* 0x5A Z */
|
||||
morkCh_kV, /* 0x5B [ */
|
||||
0, /* 0x5C \ cannot be kV because needs escape */
|
||||
morkCh_kV, /* 0x5D ] */
|
||||
morkCh_kV, /* 0x5E ^ */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM, /* 0x5F _ */
|
||||
|
||||
morkCh_kV, /* 0x60 ` */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x61 a */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x62 b */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x63 c */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x64 d */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x65 e */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL|morkCh_kX, /* 0x66 f */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x67 g */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x68 h */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x69 i */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6A j */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6B k */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6C l */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6D m */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6E n */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x6F o */
|
||||
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x70 p */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x71 q */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x72 r */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x73 s */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x74 t */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x75 u */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x76 v */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x77 w */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x78 x */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x79 y */
|
||||
morkCh_kV|morkCh_kN|morkCh_kM|morkCh_kL, /* 0x7A z */
|
||||
morkCh_kV, /* 0x7B { */
|
||||
morkCh_kV, /* 0x7C | */
|
||||
morkCh_kV, /* 0x7D } */
|
||||
morkCh_kV, /* 0x7E ~ */
|
||||
morkCh_kW, /* 0x7F rubout */
|
||||
|
||||
/* $"80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
/* $"F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF" */
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,126 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKCH_
|
||||
#define _MORKCH_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
/* this byte char predicate header file derives from public domain Mithril */
|
||||
/* (that means much of this has a copyright dedicated to the public domain) */
|
||||
|
||||
/* Use all 8 pred bits; lose some pred bits only if we need to reuse them. */
|
||||
|
||||
/* ch pred bits: W:white D:digit V:value U:upper L:lower N:name M:more */
|
||||
#define morkCh_kW (1 << 0)
|
||||
#define morkCh_kD (1 << 1)
|
||||
#define morkCh_kV (1 << 2)
|
||||
#define morkCh_kU (1 << 3)
|
||||
#define morkCh_kL (1 << 4)
|
||||
#define morkCh_kX (1 << 5)
|
||||
#define morkCh_kN (1 << 6)
|
||||
#define morkCh_kM (1 << 7)
|
||||
|
||||
extern const mork_flags morkCh_Type[]; /* 256 byte predicate bits ch map */
|
||||
|
||||
/* is a numeric decimal digit: (note memory access might be slower) */
|
||||
/* define morkCh_IsDigit(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kD ) */
|
||||
#define morkCh_IsDigit(c) ( ((mork_ch) c) >= '0' && ((mork_ch) c) <= '9' )
|
||||
|
||||
/* is a numeric octal digit: */
|
||||
#define morkCh_IsOctal(c) ( ((mork_ch) c) >= '0' && ((mork_ch) c) <= '7' )
|
||||
|
||||
/* is a numeric hexadecimal digit: */
|
||||
#define morkCh_IsHex(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kX )
|
||||
|
||||
/* is value (can be printed in Mork value without needing hex or escape): */
|
||||
#define morkCh_IsValue(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kV )
|
||||
|
||||
/* is white space : */
|
||||
#define morkCh_IsWhite(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kW )
|
||||
|
||||
/* is name (can start a Mork name): */
|
||||
#define morkCh_IsName(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kN )
|
||||
|
||||
/* is name (can continue a Mork name): */
|
||||
#define morkCh_IsMore(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kM )
|
||||
|
||||
/* is alphabetic upper or lower case */
|
||||
#define morkCh_IsAlpha(c) \
|
||||
( morkCh_Type[ (mork_ch)(c) ] & (morkCh_kL|morkCh_kU) )
|
||||
|
||||
/* is alphanumeric, including lower case, upper case, and digits */
|
||||
#define morkCh_IsAlphaNum(c) \
|
||||
(morkCh_Type[ (mork_ch)(c) ]&(morkCh_kL|morkCh_kU|morkCh_kD))
|
||||
|
||||
/* ````` repeated testing of predicate bits in single flag byte ````` */
|
||||
|
||||
#define morkCh_GetFlags(c) ( morkCh_Type[ (mork_ch)(c) ] )
|
||||
|
||||
#define morkFlags_IsDigit(f) ( (f) & morkCh_kD )
|
||||
#define morkFlags_IsHex(f) ( (f) & morkCh_kX )
|
||||
#define morkFlags_IsValue(f) ( (f) & morkCh_kV )
|
||||
#define morkFlags_IsWhite(f) ( (f) & morkCh_kW )
|
||||
#define morkFlags_IsName(f) ( (f) & morkCh_kN )
|
||||
#define morkFlags_IsMore(f) ( (f) & morkCh_kM )
|
||||
#define morkFlags_IsAlpha(f) ( (f) & (morkCh_kL|morkCh_kU) )
|
||||
#define morkFlags_IsAlphaNum(f) ( (f) & (morkCh_kL|morkCh_kU|morkCh_kD) )
|
||||
|
||||
#define morkFlags_IsUpper(f) ( (f) & morkCh_kU )
|
||||
#define morkFlags_IsLower(f) ( (f) & morkCh_kL )
|
||||
|
||||
/* ````` character case (e.g. for case insensitive operations) ````` */
|
||||
|
||||
|
||||
#define morkCh_IsAscii(c) ( ((mork_u1) c) <= 0x7F )
|
||||
#define morkCh_IsSevenBitChar(c) ( ((mork_u1) c) <= 0x7F )
|
||||
|
||||
/* ````` character case (e.g. for case insensitive operations) ````` */
|
||||
|
||||
#define morkCh_ToLower(c) ((c)-'A'+'a')
|
||||
#define morkCh_ToUpper(c) ((c)-'a'+'A')
|
||||
|
||||
/* extern int morkCh_IsUpper (int c); */
|
||||
#define morkCh_IsUpper(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kU )
|
||||
|
||||
/* extern int morkCh_IsLower (int c); */
|
||||
#define morkCh_IsLower(c) ( morkCh_Type[ (mork_ch)(c) ] & morkCh_kL )
|
||||
|
||||
#endif
|
||||
/* _MORKCH_ */
|
|
@ -0,0 +1,260 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCONFIG_
|
||||
#include "morkConfig.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
void mork_assertion_signal(const char* inMessage)
|
||||
{
|
||||
#if defined(MORK_WIN) || defined(MORK_MAC)
|
||||
// asm { int 3 }
|
||||
NS_ERROR(inMessage);
|
||||
#endif /*MORK_WIN*/
|
||||
}
|
||||
|
||||
#if defined(MORK_OS2)
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <share.h>
|
||||
#include <io.h>
|
||||
|
||||
FILE* mork_fileopen(const char* name, const char* mode)
|
||||
{
|
||||
int access = O_RDWR;
|
||||
int descriptor;
|
||||
int pmode = 0;
|
||||
|
||||
/* Only possible options are wb+ and rb+ */
|
||||
MORK_ASSERT((mode[0] == 'w' || mode[0] == 'r') && (mode[1] == 'b') && (mode[2] == '+'));
|
||||
if (mode[0] == 'w') {
|
||||
access |= (O_TRUNC | O_CREAT);
|
||||
pmode = S_IREAD | S_IWRITE;
|
||||
}
|
||||
|
||||
descriptor = sopen(name, access, SH_DENYNO, pmode);
|
||||
if (descriptor != -1) {
|
||||
return fdopen(descriptor, mode);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MORK_PROVIDE_STDLIB
|
||||
|
||||
MORK_LIB_IMPL(mork_i4)
|
||||
mork_memcmp(const void* inOne, const void* inTwo, mork_size inSize)
|
||||
{
|
||||
register const mork_u1* t = (const mork_u1*) inTwo;
|
||||
register const mork_u1* s = (const mork_u1*) inOne;
|
||||
const mork_u1* end = s + inSize;
|
||||
register mork_i4 delta;
|
||||
|
||||
while ( s < end )
|
||||
{
|
||||
delta = ((mork_i4) *s) - ((mork_i4) *t);
|
||||
if ( delta )
|
||||
return delta;
|
||||
else
|
||||
{
|
||||
++t;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(void)
|
||||
mork_memcpy(void* outDst, const void* inSrc, mork_size inSize)
|
||||
{
|
||||
register mork_u1* d = (mork_u1*) outDst;
|
||||
mork_u1* end = d + inSize;
|
||||
register const mork_u1* s = ((const mork_u1*) inSrc);
|
||||
|
||||
while ( inSize >= 8 )
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
|
||||
inSize -= 8;
|
||||
}
|
||||
|
||||
while ( d < end )
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(void)
|
||||
mork_memmove(void* outDst, const void* inSrc, mork_size inSize)
|
||||
{
|
||||
register mork_u1* d = (mork_u1*) outDst;
|
||||
register const mork_u1* s = (const mork_u1*) inSrc;
|
||||
if ( d != s && inSize ) // copy is necessary?
|
||||
{
|
||||
const mork_u1* srcEnd = s + inSize; // one past last source byte
|
||||
|
||||
if ( d > s && d < srcEnd ) // overlap? need to copy backwards?
|
||||
{
|
||||
s = srcEnd; // start one past last source byte
|
||||
d += inSize; // start one past last dest byte
|
||||
mork_u1* dstBegin = d; // last byte to write is first in dest range
|
||||
while ( d - dstBegin >= 8 )
|
||||
{
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
*--d = *--s;
|
||||
}
|
||||
while ( d > dstBegin )
|
||||
*--d = *--s;
|
||||
}
|
||||
else // can copy forwards without any overlap
|
||||
{
|
||||
mork_u1* dstEnd = d + inSize;
|
||||
while ( dstEnd - d >= 8 )
|
||||
{
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
*d++ = *s++;
|
||||
}
|
||||
while ( d < dstEnd )
|
||||
*d++ = *s++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(void)
|
||||
mork_memset(void* outDst, int inByte, mork_size inSize)
|
||||
{
|
||||
register mork_u1* d = (mork_u1*) outDst;
|
||||
mork_u1* end = d + inSize;
|
||||
while ( d < end )
|
||||
*d++ = (mork_u1) inByte;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(void)
|
||||
mork_strcpy(void* outDst, const void* inSrc)
|
||||
{
|
||||
// back up one first to support preincrement
|
||||
register mork_u1* d = ((mork_u1*) outDst) - 1;
|
||||
register const mork_u1* s = ((const mork_u1*) inSrc) - 1;
|
||||
while ( ( *++d = *++s ) != 0 )
|
||||
/* empty */;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(mork_i4)
|
||||
mork_strcmp(const void* inOne, const void* inTwo)
|
||||
{
|
||||
register const mork_u1* t = (const mork_u1*) inTwo;
|
||||
register const mork_u1* s = ((const mork_u1*) inOne);
|
||||
register mork_i4 a;
|
||||
register mork_i4 b;
|
||||
register mork_i4 delta;
|
||||
|
||||
do
|
||||
{
|
||||
a = (mork_i4) *s++;
|
||||
b = (mork_i4) *t++;
|
||||
delta = a - b;
|
||||
}
|
||||
while ( !delta && a && b );
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(mork_i4)
|
||||
mork_strncmp(const void* inOne, const void* inTwo, mork_size inSize)
|
||||
{
|
||||
register const mork_u1* t = (const mork_u1*) inTwo;
|
||||
register const mork_u1* s = (const mork_u1*) inOne;
|
||||
const mork_u1* end = s + inSize;
|
||||
register mork_i4 delta;
|
||||
register mork_i4 a;
|
||||
register mork_i4 b;
|
||||
|
||||
while ( s < end )
|
||||
{
|
||||
a = (mork_i4) *s++;
|
||||
b = (mork_i4) *t++;
|
||||
delta = a - b;
|
||||
if ( delta || !a || !b )
|
||||
return delta;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MORK_LIB_IMPL(mork_size)
|
||||
mork_strlen(const void* inString)
|
||||
{
|
||||
// back up one first to support preincrement
|
||||
register const mork_u1* s = ((const mork_u1*) inString) - 1;
|
||||
while ( *++s ) // preincrement is cheapest
|
||||
/* empty */;
|
||||
|
||||
return s - ((const mork_u1*) inString); // distance from original address
|
||||
}
|
||||
|
||||
#endif /*MORK_PROVIDE_STDLIB*/
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,198 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKCONFIG_
|
||||
#define _MORKCONFIG_ 1
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// { %%%%% begin debug mode options in Mork %%%%%
|
||||
#define MORK_DEBUG 1
|
||||
// } %%%%% end debug mode options in Mork %%%%%
|
||||
|
||||
#ifdef MORK_DEBUG
|
||||
#define MORK_MAX_CODE_COMPILE 1
|
||||
#endif
|
||||
|
||||
// { %%%%% begin platform defs peculiar to Mork %%%%%
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
#define MORK_MAC 1
|
||||
#endif
|
||||
|
||||
#ifdef XP_OS2
|
||||
#define MORK_OS2 1
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
#define MORK_WIN 1
|
||||
#endif
|
||||
|
||||
#ifdef XP_UNIX
|
||||
#define MORK_UNIX 1
|
||||
#endif
|
||||
|
||||
// } %%%%% end platform defs peculiar to Mork %%%%%
|
||||
|
||||
#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) || defined(MORK_OS2)
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_MEMORY_H
|
||||
#include <memory.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* for SEEK_SET, SEEK_END */
|
||||
#endif
|
||||
|
||||
#include "nsDebug.h"
|
||||
|
||||
#define MORK_ISPRINT(c) isprint(c)
|
||||
|
||||
#define MORK_FILETELL(file) ftell(file)
|
||||
#define MORK_FILESEEK(file, where, how) fseek(file, where, how)
|
||||
#define MORK_FILEREAD(outbuf, insize, file) fread(outbuf, 1, insize, file)
|
||||
#if defined(MORK_WIN)
|
||||
void mork_fileflush(FILE * file);
|
||||
#define MORK_FILEFLUSH(file) mork_fileflush(file)
|
||||
#else
|
||||
#define MORK_FILEFLUSH(file) fflush(file)
|
||||
#endif /*MORK_WIN*/
|
||||
|
||||
#if defined(MORK_OS2)
|
||||
FILE* mork_fileopen(const char* name, const char* mode);
|
||||
#define MORK_FILEOPEN(file, how) mork_fileopen(file, how)
|
||||
#else
|
||||
#define MORK_FILEOPEN(file, how) fopen(file, how)
|
||||
#endif
|
||||
#define MORK_FILECLOSE(file) fclose(file)
|
||||
#endif /*MORK_WIN*/
|
||||
|
||||
/* ===== separating switchable features ===== */
|
||||
|
||||
#define MORK_ENABLE_ZONE_ARENAS 1 /* using morkZone for pooling */
|
||||
|
||||
//#define MORK_ENABLE_PROBE_MAPS 1 /* use smaller hash tables */
|
||||
|
||||
#define MORK_BEAD_OVER_NODE_MAPS 1 /* use bead not node maps */
|
||||
|
||||
/* ===== pooling ===== */
|
||||
|
||||
#if defined(HAVE_64BIT_OS)
|
||||
#define MORK_CONFIG_ALIGN_8 1 /* must have 8 byte alignment */
|
||||
#else
|
||||
#define MORK_CONFIG_PTR_SIZE_4 1 /* sizeof(void*) == 4 */
|
||||
#endif
|
||||
|
||||
// #define MORK_DEBUG_HEAP_STATS 1 /* analyze per-block heap usage */
|
||||
|
||||
/* ===== ===== ===== ===== line characters ===== ===== ===== ===== */
|
||||
#define mork_kCR 0x0D
|
||||
#define mork_kLF 0x0A
|
||||
#define mork_kVTAB '\013'
|
||||
#define mork_kFF '\014'
|
||||
#define mork_kTAB '\011'
|
||||
#define mork_kCRLF "\015\012" /* A CR LF equivalent string */
|
||||
|
||||
#if defined(MORK_MAC)
|
||||
# define mork_kNewline "\015"
|
||||
# define mork_kNewlineSize 1
|
||||
#else
|
||||
# if defined(MORK_WIN) || defined(MORK_OS2)
|
||||
# define mork_kNewline "\015\012"
|
||||
# define mork_kNewlineSize 2
|
||||
# else
|
||||
# if defined(MORK_UNIX)
|
||||
# define mork_kNewline "\012"
|
||||
# define mork_kNewlineSize 1
|
||||
# endif /* MORK_UNIX */
|
||||
# endif /* MORK_WIN */
|
||||
#endif /* MORK_MAC */
|
||||
|
||||
// { %%%%% begin assertion macro %%%%%
|
||||
extern void mork_assertion_signal(const char* inMessage);
|
||||
#define MORK_ASSERTION_SIGNAL(Y) mork_assertion_signal(Y)
|
||||
#define MORK_ASSERT(X) if (!(X)) MORK_ASSERTION_SIGNAL(#X)
|
||||
// } %%%%% end assertion macro %%%%%
|
||||
|
||||
#define MORK_LIB(return) return /*API return declaration*/
|
||||
#define MORK_LIB_IMPL(return) return /*implementation return declaration*/
|
||||
|
||||
// { %%%%% begin standard c utility methods %%%%%
|
||||
|
||||
#if defined(MORK_WIN) || defined(MORK_UNIX) || defined(MORK_MAC) || defined(MORK_OS2)
|
||||
#define MORK_USE_C_STDLIB 1
|
||||
#endif /*MORK_WIN*/
|
||||
|
||||
#ifdef MORK_USE_C_STDLIB
|
||||
#define MORK_MEMCMP(src1,src2,size) memcmp(src1,src2,size)
|
||||
#define MORK_MEMCPY(dest,src,size) memcpy(dest,src,size)
|
||||
#define MORK_MEMMOVE(dest,src,size) memmove(dest,src,size)
|
||||
#define MORK_MEMSET(dest,byte,size) memset(dest,byte,size)
|
||||
#define MORK_STRCPY(dest,src) strcpy(dest,src)
|
||||
#define MORK_STRCMP(one,two) strcmp(one,two)
|
||||
#define MORK_STRNCMP(one,two,length) strncmp(one,two,length)
|
||||
#define MORK_STRLEN(string) strlen(string)
|
||||
#endif /*MORK_USE_C_STDLIB*/
|
||||
|
||||
#ifdef MORK_PROVIDE_STDLIB
|
||||
MORK_LIB(mork_i4) mork_memcmp(const void* a, const void* b, mork_size inSize);
|
||||
MORK_LIB(void) mork_memcpy(void* dst, const void* src, mork_size inSize);
|
||||
MORK_LIB(void) mork_memmove(void* dst, const void* src, mork_size inSize);
|
||||
MORK_LIB(void) mork_memset(void* dst, int inByte, mork_size inSize);
|
||||
MORK_LIB(void) mork_strcpy(void* dst, const void* src);
|
||||
MORK_LIB(mork_i4) mork_strcmp(const void* a, const void* b);
|
||||
MORK_LIB(mork_i4) mork_strncmp(const void* a, const void* b, mork_size inSize);
|
||||
MORK_LIB(mork_size) mork_strlen(const void* inString);
|
||||
|
||||
#define MORK_MEMCMP(src1,src2,size) mork_memcmp(src1,src2,size)
|
||||
#define MORK_MEMCPY(dest,src,size) mork_memcpy(dest,src,size)
|
||||
#define MORK_MEMMOVE(dest,src,size) mork_memmove(dest,src,size)
|
||||
#define MORK_MEMSET(dest,byte,size) mork_memset(dest,byte,size)
|
||||
#define MORK_STRCPY(dest,src) mork_strcpy(dest,src)
|
||||
#define MORK_STRCMP(one,two) mork_strcmp(one,two)
|
||||
#define MORK_STRNCMP(one,two,length) mork_strncmp(one,two,length)
|
||||
#define MORK_STRLEN(string) mork_strlen(string)
|
||||
#endif /*MORK_PROVIDE_STDLIB*/
|
||||
|
||||
// } %%%%% end standard c utility methods %%%%%
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKCONFIG_ */
|
||||
|
|
@ -0,0 +1,218 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkCursor::CloseMorkNode(morkEnv* ev) // CloseCursor() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkCursor::~morkCursor() // assert CloseCursor() executed earlier
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkCursor::morkCursor(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mCursor_Seed( 0 )
|
||||
, mCursor_Pos( -1 )
|
||||
, mCursor_DoFailOnSeedOutOfSync( morkBool_kFalse )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kCursor;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkCursor, morkObject, nsIMdbCursor)
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkCursor::CloseCursor(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mCursor_Seed = 0;
|
||||
mCursor_Pos = -1;
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
*outCount = WeakRefsOnly();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
*outCount = StrongRefsOnly();
|
||||
return NS_OK;
|
||||
}
|
||||
// ### TODO - clean up this cast, if required
|
||||
NS_IMETHODIMP
|
||||
morkCursor::AddWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::AddWeakRef((morkEnv *) mev);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkCursor::AddStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::AddStrongRef((morkEnv *) mev);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::CutWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CutWeakRef((morkEnv *) mev);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkCursor::CutStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CutStrongRef((morkEnv *) mev);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::CloseMdbObject(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CloseMdbObject((morkEnv *) mev);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
|
||||
{
|
||||
*outOpen = IsOpenNode();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkCursor::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
|
||||
{
|
||||
*outIsReadonly = IsFrozen();
|
||||
return NS_OK;
|
||||
}
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetCount(nsIMdbEnv* mev, mdb_count* outCount)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::SetPos(nsIMdbEnv* mev, mdb_pos inPos)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetPos(nsIMdbEnv* mev, mdb_pos* outPos)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::SetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool inFail)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkCursor::GetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool* outFail)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#define _MORKCURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kCursor /*i*/ 0x4375 /* ascii 'Cu' */
|
||||
|
||||
class morkCursor : public morkObject, public nsIMdbCursor{ // collection iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly);
|
||||
// same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev, // weak refs
|
||||
mdb_count* outCount);
|
||||
NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev, // strong refs
|
||||
mdb_count* outCount);
|
||||
|
||||
NS_IMETHOD AddWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD AddStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CutWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD CutStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); // called at strong refs zero
|
||||
NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen);
|
||||
// } ----- end ref counting -----
|
||||
|
||||
// } ===== end nsIMdbObject methods =====
|
||||
|
||||
// { ===== begin nsIMdbCursor methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetCount(nsIMdbEnv* ev, mdb_count* outCount); // readonly
|
||||
NS_IMETHOD GetSeed(nsIMdbEnv* ev, mdb_seed* outSeed); // readonly
|
||||
|
||||
NS_IMETHOD SetPos(nsIMdbEnv* ev, mdb_pos inPos); // mutable
|
||||
NS_IMETHOD GetPos(nsIMdbEnv* ev, mdb_pos* outPos);
|
||||
|
||||
NS_IMETHOD SetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool inFail);
|
||||
NS_IMETHOD GetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool* outFail);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// } ===== end nsIMdbCursor methods =====
|
||||
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
mork_seed mCursor_Seed;
|
||||
mork_pos mCursor_Pos;
|
||||
mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseCursor() only if open
|
||||
virtual ~morkCursor(); // assert that CloseCursor() executed earlier
|
||||
|
||||
public: // morkCursor construction & destruction
|
||||
morkCursor(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
|
||||
void CloseCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkCursor(const morkCursor& other);
|
||||
morkCursor& operator=(const morkCursor& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsCursor() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // other cursor methods
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakCursor(morkCursor* me,
|
||||
morkEnv* ev, morkCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongCursor(morkCursor* me,
|
||||
morkEnv* ev, morkCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKCURSOR_ */
|
|
@ -0,0 +1,300 @@
|
|||
/*************************************************************************
|
||||
This software is part of a public domain IronDoc source code distribution,
|
||||
and is provided on an "AS IS" basis, with all risks borne by the consumers
|
||||
or users of the IronDoc software. There are no warranties, guarantees, or
|
||||
promises about quality of any kind; and no remedies for failure exist.
|
||||
|
||||
Permission is hereby granted to use this IronDoc software for any purpose
|
||||
at all, without need for written agreements, without royalty or license
|
||||
fees, and without fees or obligations of any other kind. Anyone can use,
|
||||
copy, change and distribute this software for any purpose, and nothing is
|
||||
required, implicitly or otherwise, in exchange for this usage.
|
||||
|
||||
You cannot apply your own copyright to this software, but otherwise you
|
||||
are encouraged to enjoy the use of this software in any way you see fit.
|
||||
However, it would be rude to remove names of developers from the code.
|
||||
(IronDoc is also known by the short name "Fe" and a longer name "Ferrum",
|
||||
which are used interchangeably with the name IronDoc in the sources.)
|
||||
*************************************************************************/
|
||||
/*
|
||||
* File: morkDeque.cpp
|
||||
* Contains: Ferrum deque (double ended queue (linked list))
|
||||
*
|
||||
* Copied directly from public domain IronDoc, with minor naming tweaks:
|
||||
* Designed and written by David McCusker, but all this code is public domain.
|
||||
* There are no warranties, no guarantees, no promises, and no remedies.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkNext::morkNext() : mNext_Link( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkNext::MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* next = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &next);
|
||||
if ( !next )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkNext::ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
morkList::morkList() : mList_Head( 0 ), mList_Tail( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void morkList::CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
morkNext* next = 0;
|
||||
while ( (next = this->PopHead()) != 0 )
|
||||
next->ZapOldNext(ev, ioHeap);
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
void morkList::CutAllListMembers()
|
||||
// just make list empty, dropping members without zapping
|
||||
{
|
||||
while ( this->PopHead() )
|
||||
/* empty */;
|
||||
|
||||
mList_Head = 0;
|
||||
mList_Tail = 0;
|
||||
}
|
||||
|
||||
morkNext* morkList::PopHead() // cut head of list
|
||||
{
|
||||
morkNext* outHead = mList_Head;
|
||||
if ( outHead ) // anything to cut from list?
|
||||
{
|
||||
morkNext* next = outHead->mNext_Link;
|
||||
mList_Head = next;
|
||||
if ( !next ) // cut the last member, so tail no longer exists?
|
||||
mList_Tail = 0;
|
||||
|
||||
outHead->mNext_Link = 0; // nil outgoing node link; unnecessary, but tidy
|
||||
}
|
||||
return outHead;
|
||||
}
|
||||
|
||||
|
||||
void morkList::PushHead(morkNext* ioLink) // add to head of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = head; // make old head follow the new link
|
||||
if ( !head ) // list was previously empty?
|
||||
mList_Tail = ioLink; // head is also tail for first member added
|
||||
|
||||
mList_Head = ioLink; // head of list is the new link
|
||||
}
|
||||
|
||||
void morkList::PushTail(morkNext* ioLink) // add to tail of list
|
||||
{
|
||||
morkNext* head = mList_Head; // old head of list
|
||||
morkNext* tail = mList_Tail; // old tail of list
|
||||
|
||||
MORK_ASSERT( (head && tail) || (!head && !tail));
|
||||
|
||||
ioLink->mNext_Link = 0;
|
||||
if ( tail )
|
||||
{
|
||||
tail->mNext_Link = ioLink;
|
||||
mList_Tail = ioLink;
|
||||
}
|
||||
else // list was previously empty?
|
||||
mList_Head = mList_Tail = ioLink; // tail is also head for first member added
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
||||
morkLink::morkLink() : mLink_Next( 0 ), mLink_Prev( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ void*
|
||||
morkLink::MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* alink = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void**) &alink);
|
||||
if ( !alink )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return alink;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
void morkLink::ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
if ( this )
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
* morkDeque: doubly linked list modeled after VAX queue instructions
|
||||
*/
|
||||
|
||||
morkDeque::morkDeque()
|
||||
{
|
||||
mDeque_Head.SelfRefer();
|
||||
}
|
||||
|
||||
|
||||
/*| RemoveFirst:
|
||||
|*/
|
||||
morkLink*
|
||||
morkDeque::RemoveFirst() /*i*/
|
||||
{
|
||||
morkLink* alink = mDeque_Head.mLink_Next;
|
||||
if ( alink != &mDeque_Head )
|
||||
{
|
||||
(mDeque_Head.mLink_Next = alink->mLink_Next)->mLink_Prev =
|
||||
&mDeque_Head;
|
||||
return alink;
|
||||
}
|
||||
return (morkLink*) 0;
|
||||
}
|
||||
|
||||
/*| RemoveLast:
|
||||
|*/
|
||||
morkLink*
|
||||
morkDeque::RemoveLast() /*i*/
|
||||
{
|
||||
morkLink* alink = mDeque_Head.mLink_Prev;
|
||||
if ( alink != &mDeque_Head )
|
||||
{
|
||||
(mDeque_Head.mLink_Prev = alink->mLink_Prev)->mLink_Next =
|
||||
&mDeque_Head;
|
||||
return alink;
|
||||
}
|
||||
return (morkLink*) 0;
|
||||
}
|
||||
|
||||
/*| At:
|
||||
|*/
|
||||
morkLink*
|
||||
morkDeque::At(mork_pos index) const /*i*/
|
||||
/* indexes are one based (and not zero based) */
|
||||
{
|
||||
register mork_num count = 0;
|
||||
register morkLink* alink;
|
||||
for ( alink = this->First(); alink; alink = this->After(alink) )
|
||||
{
|
||||
if ( ++count == (mork_num) index )
|
||||
break;
|
||||
}
|
||||
return alink;
|
||||
}
|
||||
|
||||
/*| IndexOf:
|
||||
|*/
|
||||
mork_pos
|
||||
morkDeque::IndexOf(const morkLink* member) const /*i*/
|
||||
/* indexes are one based (and not zero based) */
|
||||
/* zero means member is not in deque */
|
||||
{
|
||||
register mork_num count = 0;
|
||||
register const morkLink* alink;
|
||||
for ( alink = this->First(); alink; alink = this->After(alink) )
|
||||
{
|
||||
++count;
|
||||
if ( member == alink )
|
||||
return (mork_pos) count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*| Length:
|
||||
|*/
|
||||
mork_num
|
||||
morkDeque::Length() const /*i*/
|
||||
{
|
||||
register mork_num count = 0;
|
||||
register morkLink* alink;
|
||||
for ( alink = this->First(); alink; alink = this->After(alink) )
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*| LengthCompare:
|
||||
|*/
|
||||
int
|
||||
morkDeque::LengthCompare(mork_num c) const /*i*/
|
||||
{
|
||||
register mork_num count = 0;
|
||||
register const morkLink* alink;
|
||||
for ( alink = this->First(); alink; alink = this->After(alink) )
|
||||
{
|
||||
if ( ++count > c )
|
||||
return 1;
|
||||
}
|
||||
return ( count == c )? 0 : -1;
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
/*************************************************************************
|
||||
This software is part of a public domain IronDoc source code distribution,
|
||||
and is provided on an "AS IS" basis, with all risks borne by the consumers
|
||||
or users of the IronDoc software. There are no warranties, guarantees, or
|
||||
promises about quality of any kind; and no remedies for failure exist.
|
||||
|
||||
Permission is hereby granted to use this IronDoc software for any purpose
|
||||
at all, without need for written agreements, without royalty or license
|
||||
fees, and without fees or obligations of any other kind. Anyone can use,
|
||||
copy, change and distribute this software for any purpose, and nothing is
|
||||
required, implicitly or otherwise, in exchange for this usage.
|
||||
|
||||
You cannot apply your own copyright to this software, but otherwise you
|
||||
are encouraged to enjoy the use of this software in any way you see fit.
|
||||
However, it would be rude to remove names of developers from the code.
|
||||
(IronDoc is also known by the short name "Fe" and a longer name "Ferrum",
|
||||
which are used interchangeably with the name IronDoc in the sources.)
|
||||
*************************************************************************/
|
||||
/*
|
||||
* File: morkDeque.h
|
||||
* Contains: Ferrum deque (double ended queue (linked list))
|
||||
*
|
||||
* Copied directly from public domain IronDoc, with minor naming tweaks:
|
||||
* Designed and written by David McCusker, but all this code is public domain.
|
||||
* There are no warranties, no guarantees, no promises, and no remedies.
|
||||
*/
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#define _MORKDEQUE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
/*=============================================================================
|
||||
* morkNext: linked list node for very simple, singly-linked list
|
||||
*/
|
||||
|
||||
class morkNext /*d*/ {
|
||||
public:
|
||||
morkNext* mNext_Link;
|
||||
|
||||
public:
|
||||
morkNext(int inZero) : mNext_Link( 0 ) { }
|
||||
|
||||
morkNext(morkNext* ioLink) : mNext_Link( ioLink ) { }
|
||||
|
||||
morkNext(); // mNext_Link( 0 ), { }
|
||||
|
||||
public:
|
||||
morkNext* GetNextLink() const { return mNext_Link; }
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewNext(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldNext(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkNext::MakeNewNext(inSize, ioHeap, ev); }
|
||||
|
||||
void operator delete(void* ioAddress) // DO NOT CALL THIS, hope to crash:
|
||||
{ ((morkNext*) 0)->ZapOldNext((morkEnv*) 0, (nsIMdbHeap*) 0); } // boom
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkList: simple, singly-linked list
|
||||
*/
|
||||
|
||||
/*| morkList: a list of singly-linked members (instances of morkNext), where
|
||||
**| the number of list members might be so numerous that we must about cost
|
||||
**| for two pointer link slots per member (as happens with morkLink).
|
||||
**|
|
||||
**|| morkList is intended to support lists of changes in morkTable, where we
|
||||
**| are worried about the space cost of representing such changes. (Later we
|
||||
**| can use an array instead, when we get even more worried, to avoid cost
|
||||
**| of link slots at all, per member).
|
||||
**|
|
||||
**|| Do NOT create cycles in links using this list class, since we do not
|
||||
**| deal with them very nicely.
|
||||
|*/
|
||||
class morkList /*d*/ {
|
||||
public:
|
||||
morkNext* mList_Head; // first link in the list
|
||||
morkNext* mList_Tail; // last link in the list
|
||||
|
||||
public:
|
||||
morkNext* GetListHead() const { return mList_Head; }
|
||||
morkNext* GetListTail() const { return mList_Tail; }
|
||||
|
||||
mork_bool IsListEmpty() const { return ( mList_Head == 0 ); }
|
||||
mork_bool HasListMembers() const { return ( mList_Head != 0 ); }
|
||||
|
||||
public:
|
||||
morkList(); // : mList_Head( 0 ), mList_Tail( 0 ) { }
|
||||
|
||||
void CutAndZapAllListMembers(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
// make empty list, zapping every member by calling ZapOldNext()
|
||||
|
||||
void CutAllListMembers();
|
||||
// just make list empty, dropping members without zapping
|
||||
|
||||
public:
|
||||
morkNext* PopHead(); // cut head of list
|
||||
|
||||
// Note we don't support PopTail(), so use morkDeque if you need that.
|
||||
|
||||
void PushHead(morkNext* ioLink); // add to head of list
|
||||
void PushTail(morkNext* ioLink); // add to tail of list
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkLink: linked list node embedded in objs to allow insertion in morkDeques
|
||||
*/
|
||||
|
||||
class morkLink /*d*/ {
|
||||
public:
|
||||
morkLink* mLink_Next;
|
||||
morkLink* mLink_Prev;
|
||||
|
||||
public:
|
||||
morkLink(int inZero) : mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
morkLink(); // mLink_Next( 0 ), mLink_Prev( 0 ) { }
|
||||
|
||||
public:
|
||||
morkLink* Next() const { return mLink_Next; }
|
||||
morkLink* Prev() const { return mLink_Prev; }
|
||||
|
||||
void SelfRefer() { mLink_Next = mLink_Prev = this; }
|
||||
void Clear() { mLink_Next = mLink_Prev = 0; }
|
||||
|
||||
void AddBefore(morkLink* old)
|
||||
{
|
||||
((old)->mLink_Prev->mLink_Next = (this))->mLink_Prev = (old)->mLink_Prev;
|
||||
((this)->mLink_Next = (old))->mLink_Prev = this;
|
||||
}
|
||||
|
||||
void AddAfter(morkLink* old)
|
||||
{
|
||||
((old)->mLink_Next->mLink_Prev = (this))->mLink_Next = (old)->mLink_Next;
|
||||
((this)->mLink_Prev = (old))->mLink_Next = this;
|
||||
}
|
||||
|
||||
void Remove()
|
||||
{
|
||||
(mLink_Prev->mLink_Next = mLink_Next)->mLink_Prev = mLink_Prev;
|
||||
}
|
||||
|
||||
public: // link memory management methods
|
||||
static void* MakeNewLink(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
void ZapOldLink(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
public: // link memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkLink::MakeNewLink(inSize, ioHeap, ev); }
|
||||
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkDeque: doubly linked list modeled after VAX queue instructions
|
||||
*/
|
||||
|
||||
class morkDeque /*d*/ {
|
||||
public:
|
||||
morkLink mDeque_Head;
|
||||
|
||||
public: // construction
|
||||
morkDeque(); // { mDeque_Head.SelfRefer(); }
|
||||
|
||||
public:// methods
|
||||
morkLink* RemoveFirst();
|
||||
|
||||
morkLink* RemoveLast();
|
||||
|
||||
morkLink* At(mork_pos index) const ; /* one-based, not zero-based */
|
||||
|
||||
mork_pos IndexOf(const morkLink* inMember) const;
|
||||
/* one-based index ; zero means member is not in deque */
|
||||
|
||||
mork_num Length() const;
|
||||
|
||||
/* the following method is more efficient for long lists: */
|
||||
int LengthCompare(mork_num inCount) const;
|
||||
/* -1: length < count, 0: length == count, 1: length > count */
|
||||
|
||||
public: // inlines
|
||||
|
||||
mork_bool IsEmpty()const
|
||||
{ return (mDeque_Head.mLink_Next == (morkLink*) &mDeque_Head); }
|
||||
|
||||
morkLink* After(const morkLink* old) const
|
||||
{ return (((old)->mLink_Next != &mDeque_Head)?
|
||||
(old)->mLink_Next : (morkLink*) 0); }
|
||||
|
||||
morkLink* Before(const morkLink* old) const
|
||||
{ return (((old)->mLink_Prev != &mDeque_Head)?
|
||||
(old)->mLink_Prev : (morkLink*) 0); }
|
||||
|
||||
morkLink* First() const
|
||||
{ return ((mDeque_Head.mLink_Next != &mDeque_Head)?
|
||||
mDeque_Head.mLink_Next : (morkLink*) 0); }
|
||||
|
||||
morkLink* Last() const
|
||||
{ return ((mDeque_Head.mLink_Prev != &mDeque_Head)?
|
||||
mDeque_Head.mLink_Prev : (morkLink*) 0); }
|
||||
|
||||
/*
|
||||
From IronDoc documentation for AddFirst:
|
||||
+--------+ +--------+ +--------+ +--------+ +--------+
|
||||
| h.next |-->| b.next | | h.next |-->| a.next |-->| b.next |
|
||||
+--------+ +--------+ ==> +--------+ +--------+ +--------+
|
||||
| h.prev |<--| b.prev | | h.prev |<--| a.prev |<--| b.prev |
|
||||
+--------+ +--------+ +--------+ +--------+ +--------+
|
||||
*/
|
||||
|
||||
void AddFirst(morkLink* in) /*i*/
|
||||
{
|
||||
( (mDeque_Head.mLink_Next->mLink_Prev =
|
||||
(in))->mLink_Next = mDeque_Head.mLink_Next,
|
||||
((in)->mLink_Prev = &mDeque_Head)->mLink_Next = (in) );
|
||||
}
|
||||
/*
|
||||
From IronDoc documentation for AddLast:
|
||||
+--------+ +--------+ +--------+ +--------+ +--------+
|
||||
| y.next |-->| h.next | | y.next |-->| z.next |-->| h.next |
|
||||
+--------+ +--------+ ==> +--------+ +--------+ +--------+
|
||||
| y.prev |<--| h.prev | | y.prev |<--| z.prev |<--| h.prev |
|
||||
+--------+ +--------+ +--------+ +--------+ +--------+
|
||||
*/
|
||||
|
||||
void AddLast(morkLink* in)
|
||||
{
|
||||
( (mDeque_Head.mLink_Prev->mLink_Next =
|
||||
(in))->mLink_Prev = mDeque_Head.mLink_Prev,
|
||||
((in)->mLink_Next = &mDeque_Head)->mLink_Prev = (in) );
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _MORKDEQUE_ */
|
|
@ -0,0 +1,667 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCH_
|
||||
#include "morkCh.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFACTORY_
|
||||
#include "morkFactory.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkEnv::CloseMorkNode(morkEnv* ev) /*i*/ // CloseEnv() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseEnv(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkEnv::~morkEnv() /*i*/ // assert CloseEnv() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
if (mEnv_Heap)
|
||||
{
|
||||
mork_bool ownsHeap = mEnv_OwnsHeap;
|
||||
nsIMdbHeap*saveHeap = mEnv_Heap;
|
||||
|
||||
if (ownsHeap)
|
||||
{
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
printf("%d blocks remaining \n", ((orkinHeap *) saveHeap)->HeapBlockCount());
|
||||
mork_u4* array = (mork_u4*) this;
|
||||
array -= 3;
|
||||
// null out heap ptr in mem block so we won't crash trying to use it to
|
||||
// delete the env.
|
||||
*array = nsnull;
|
||||
#endif // MORK_DEBUG_HEAP_STATS
|
||||
// whoops, this is our heap - hmm. Can't delete it, or not allocate env's from
|
||||
// an orkinHeap.
|
||||
delete saveHeap;
|
||||
}
|
||||
|
||||
}
|
||||
// MORK_ASSERT(mEnv_SelfAsMdbEnv==0);
|
||||
MORK_ASSERT(mEnv_ErrorHook==0);
|
||||
}
|
||||
|
||||
/* choose morkBool_kTrue or morkBool_kFalse for kBeVerbose: */
|
||||
#define morkEnv_kBeVerbose morkBool_kFalse
|
||||
|
||||
/*public non-poly*/
|
||||
morkEnv::morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap)
|
||||
: morkObject(inUsage, ioHeap, morkColor_kNone)
|
||||
, mEnv_Factory( ioFactory )
|
||||
, mEnv_Heap( ioSlotHeap )
|
||||
|
||||
, mEnv_SelfAsMdbEnv( 0 )
|
||||
, mEnv_ErrorHook( 0 )
|
||||
, mEnv_HandlePool( 0 )
|
||||
|
||||
, mEnv_ErrorCount( 0 )
|
||||
, mEnv_WarningCount( 0 )
|
||||
|
||||
, mEnv_ErrorCode( 0 )
|
||||
|
||||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkEnv_kBeVerbose )
|
||||
, mEnv_OwnsHeap ( morkBool_kFalse )
|
||||
{
|
||||
MORK_ASSERT(ioSlotHeap && ioFactory );
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
// mEnv_Heap is NOT refcounted:
|
||||
// nsIMdbHeap_SlotStrongHeap(ioSlotHeap, this, &mEnv_Heap);
|
||||
|
||||
mEnv_HandlePool = new morkPool(morkUsage::kGlobal,
|
||||
(nsIMdbHeap*) 0, ioSlotHeap);
|
||||
|
||||
MORK_ASSERT(mEnv_HandlePool);
|
||||
if ( mEnv_HandlePool && this->Good() )
|
||||
{
|
||||
mNode_Derived = morkDerived_kEnv;
|
||||
mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkEnv::morkEnv(morkEnv* ev, /*i*/
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbEnv* inSelfAsMdbEnv,
|
||||
morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mEnv_Factory( ioFactory )
|
||||
, mEnv_Heap( ioSlotHeap )
|
||||
|
||||
, mEnv_SelfAsMdbEnv( inSelfAsMdbEnv )
|
||||
, mEnv_ErrorHook( 0 )
|
||||
, mEnv_HandlePool( 0 )
|
||||
|
||||
, mEnv_ErrorCount( 0 )
|
||||
, mEnv_WarningCount( 0 )
|
||||
|
||||
, mEnv_ErrorCode( 0 )
|
||||
|
||||
, mEnv_DoTrace( morkBool_kFalse )
|
||||
, mEnv_AutoClear( morkAble_kDisabled )
|
||||
, mEnv_ShouldAbort( morkBool_kFalse )
|
||||
, mEnv_BeVerbose( morkEnv_kBeVerbose )
|
||||
, mEnv_OwnsHeap ( morkBool_kFalse )
|
||||
{
|
||||
// $$$ do we need to refcount the inSelfAsMdbEnv nsIMdbEnv??
|
||||
|
||||
if ( ioFactory && inSelfAsMdbEnv && ioSlotHeap)
|
||||
{
|
||||
// mEnv_Heap is NOT refcounted:
|
||||
// nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mEnv_Heap);
|
||||
|
||||
mEnv_HandlePool = new(*ioSlotHeap, ev) morkPool(ev,
|
||||
morkUsage::kHeap, ioSlotHeap, ioSlotHeap);
|
||||
|
||||
MORK_ASSERT(mEnv_HandlePool);
|
||||
if ( mEnv_HandlePool && ev->Good() )
|
||||
{
|
||||
mNode_Derived = morkDerived_kEnv;
|
||||
mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkEnv, morkObject, nsIMdbEnv)
|
||||
/*public non-poly*/ void
|
||||
morkEnv::CloseEnv(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
// $$$ release mEnv_SelfAsMdbEnv??
|
||||
// $$$ release mEnv_ErrorHook??
|
||||
|
||||
mEnv_SelfAsMdbEnv = 0;
|
||||
mEnv_ErrorHook = 0;
|
||||
|
||||
morkPool* savePool = mEnv_HandlePool;
|
||||
morkPool::SlotStrongPool((morkPool*) 0, ev, &mEnv_HandlePool);
|
||||
// free the pool
|
||||
if (mEnv_SelfAsMdbEnv)
|
||||
{
|
||||
if (savePool && mEnv_Heap)
|
||||
mEnv_Heap->Free(this->AsMdbEnv(), savePool);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (savePool)
|
||||
{
|
||||
if (savePool->IsOpenNode())
|
||||
savePool->CloseMorkNode(ev);
|
||||
delete savePool;
|
||||
}
|
||||
// how do we free this? might need to get rid of asserts.
|
||||
}
|
||||
// mEnv_Factory is NOT refcounted
|
||||
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_size
|
||||
morkEnv::OidAsHex(void* outBuf, const mdbOid& inOid)
|
||||
// sprintf(buf, "%lX:^%lX", (long) inOid.mOid_Id, (long) inOid.mOid_Scope);
|
||||
{
|
||||
mork_u1* p = (mork_u1*) outBuf;
|
||||
mork_size outSize = this->TokenAsHex(p, inOid.mOid_Id);
|
||||
p += outSize;
|
||||
*p++ = ':';
|
||||
|
||||
mork_scope scope = inOid.mOid_Scope;
|
||||
if ( scope < 0x80 && morkCh_IsName((mork_ch) scope) )
|
||||
{
|
||||
*p++ = (mork_u1) scope;
|
||||
*p = 0; // null termination
|
||||
outSize += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = '^';
|
||||
mork_size scopeSize = this->TokenAsHex(p, scope);
|
||||
outSize += scopeSize + 2;
|
||||
}
|
||||
return outSize;
|
||||
}
|
||||
|
||||
|
||||
mork_u1
|
||||
morkEnv::HexToByte(mork_ch inFirstHex, mork_ch inSecondHex)
|
||||
{
|
||||
mork_u1 hi = 0; // high four hex bits
|
||||
mork_flags f = morkCh_GetFlags(inFirstHex);
|
||||
if ( morkFlags_IsDigit(f) )
|
||||
hi = (mork_u1) (inFirstHex - (mork_ch) '0');
|
||||
else if ( morkFlags_IsUpper(f) )
|
||||
hi = (mork_u1) ((inFirstHex - (mork_ch) 'A') + 10);
|
||||
else if ( morkFlags_IsLower(f) )
|
||||
hi = (mork_u1) ((inFirstHex - (mork_ch) 'a') + 10);
|
||||
|
||||
mork_u1 lo = 0; // low four hex bits
|
||||
f = morkCh_GetFlags(inSecondHex);
|
||||
if ( morkFlags_IsDigit(f) )
|
||||
lo = (mork_u1) (inSecondHex - (mork_ch) '0');
|
||||
else if ( morkFlags_IsUpper(f) )
|
||||
lo = (mork_u1) ((inSecondHex - (mork_ch) 'A') + 10);
|
||||
else if ( morkFlags_IsLower(f) )
|
||||
lo = (mork_u1) ((inSecondHex - (mork_ch) 'a') + 10);
|
||||
|
||||
return (mork_u1) ((hi << 4) | lo);
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkEnv::TokenAsHex(void* outBuf, mork_token inToken)
|
||||
// TokenAsHex() is the same as sprintf(outBuf, "%lX", (long) inToken);
|
||||
{
|
||||
static const char morkEnv_kHexDigits[] = "0123456789ABCDEF";
|
||||
char* p = (char*) outBuf;
|
||||
char* end = p + 32; // write no more than 32 digits for safety
|
||||
if ( inToken )
|
||||
{
|
||||
// first write all the hex digits in backwards order:
|
||||
while ( p < end && inToken ) // more digits to write?
|
||||
{
|
||||
*p++ = morkEnv_kHexDigits[ inToken & 0x0F ]; // low four bits
|
||||
inToken >>= 4; // we fervently hope this does not sign extend
|
||||
}
|
||||
*p = 0; // end the string with a null byte
|
||||
char* s = (char*) outBuf; // first byte in string
|
||||
mork_size size = (mork_size) (p - s); // distance from start
|
||||
|
||||
// now reverse the string in place:
|
||||
// note that p starts on the null byte, so we need predecrement:
|
||||
while ( --p > s ) // need to swap another byte in the string?
|
||||
{
|
||||
char c = *p; // temp for swap
|
||||
*p = *s;
|
||||
*s++ = c; // move s forward here, and p backward in the test
|
||||
}
|
||||
return size;
|
||||
}
|
||||
else // special case for zero integer
|
||||
{
|
||||
*p++ = '0'; // write a zero digit
|
||||
*p = 0; // end with a null byte
|
||||
return 1; // one digit in hex representation
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::StringToYarn(const char* inString, mdbYarn* outYarn)
|
||||
{
|
||||
if ( outYarn )
|
||||
{
|
||||
mdb_fill fill = ( inString )? (mdb_fill) MORK_STRLEN(inString) : 0;
|
||||
|
||||
if ( fill ) // have nonempty content?
|
||||
{
|
||||
mdb_size size = outYarn->mYarn_Size; // max dest size
|
||||
if ( fill > size ) // too much string content?
|
||||
{
|
||||
outYarn->mYarn_More = fill - size; // extra string bytes omitted
|
||||
fill = size; // copy no more bytes than size of yarn buffer
|
||||
}
|
||||
void* dest = outYarn->mYarn_Buf; // where bytes are going
|
||||
if ( !dest ) // nil destination address buffer?
|
||||
fill = 0; // we can't write any content at all
|
||||
|
||||
if ( fill ) // anything to copy?
|
||||
MORK_MEMCPY(dest, inString, fill); // copy fill bytes to yarn
|
||||
|
||||
outYarn->mYarn_Fill = fill; // tell yarn size of copied content
|
||||
}
|
||||
else // no content to put into the yarn
|
||||
{
|
||||
outYarn->mYarn_Fill = 0; // tell yarn that string has no bytes
|
||||
}
|
||||
outYarn->mYarn_Form = 0; // always update the form slot
|
||||
}
|
||||
else
|
||||
this->NilPointerError();
|
||||
}
|
||||
|
||||
char*
|
||||
morkEnv::CopyString(nsIMdbHeap* ioHeap, const char* inString)
|
||||
{
|
||||
char* outString = 0;
|
||||
if ( ioHeap && inString )
|
||||
{
|
||||
mork_size size = MORK_STRLEN(inString) + 1;
|
||||
ioHeap->Alloc(this->AsMdbEnv(), size, (void**) &outString);
|
||||
if ( outString )
|
||||
MORK_STRCPY(outString, inString);
|
||||
}
|
||||
else
|
||||
this->NilPointerError();
|
||||
return outString;
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::FreeString(nsIMdbHeap* ioHeap, char* ioString)
|
||||
{
|
||||
if ( ioHeap )
|
||||
{
|
||||
if ( ioString )
|
||||
ioHeap->Free(this->AsMdbEnv(), ioString);
|
||||
}
|
||||
else
|
||||
this->NilPointerError();
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NewErrorAndCode(const char* inString, mork_u2 inCode)
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // get developer's attention
|
||||
|
||||
++mEnv_ErrorCount;
|
||||
mEnv_ErrorCode = (mork_u4) ((inCode)? inCode: morkEnv_kGenericError);
|
||||
|
||||
if ( mEnv_ErrorHook )
|
||||
mEnv_ErrorHook->OnErrorString(this->AsMdbEnv(), inString);
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NewError(const char* inString)
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // get developer's attention
|
||||
|
||||
++mEnv_ErrorCount;
|
||||
mEnv_ErrorCode = morkEnv_kGenericError;
|
||||
|
||||
if ( mEnv_ErrorHook )
|
||||
mEnv_ErrorHook->OnErrorString(this->AsMdbEnv(), inString);
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NewWarning(const char* inString)
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // get developer's attention
|
||||
|
||||
++mEnv_WarningCount;
|
||||
if ( mEnv_ErrorHook )
|
||||
mEnv_ErrorHook->OnWarningString(this->AsMdbEnv(), inString);
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::StubMethodOnlyError()
|
||||
{
|
||||
this->NewError("method is stub only");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::OutOfMemoryError()
|
||||
{
|
||||
this->NewError("out of memory");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::CantMakeWhenBadError()
|
||||
{
|
||||
this->NewError("can't make an object when ev->Bad()");
|
||||
}
|
||||
|
||||
static const char morkEnv_kNilPointer[] = "nil pointer";
|
||||
|
||||
void
|
||||
morkEnv::NilPointerError()
|
||||
{
|
||||
this->NewError(morkEnv_kNilPointer);
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NilPointerWarning()
|
||||
{
|
||||
this->NewWarning(morkEnv_kNilPointer);
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NewNonEnvError()
|
||||
{
|
||||
this->NewError("non-env instance");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::NilEnvSlotError()
|
||||
{
|
||||
if ( !mEnv_HandlePool || !mEnv_Factory )
|
||||
{
|
||||
if ( !mEnv_HandlePool )
|
||||
this->NewError("nil mEnv_HandlePool");
|
||||
if ( !mEnv_Factory )
|
||||
this->NewError("nil mEnv_Factory");
|
||||
}
|
||||
else
|
||||
this->NewError("unknown nil env slot");
|
||||
}
|
||||
|
||||
|
||||
void morkEnv::NonEnvTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkEnv");
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::ClearMorkErrorsAndWarnings()
|
||||
{
|
||||
mEnv_ErrorCount = 0;
|
||||
mEnv_WarningCount = 0;
|
||||
mEnv_ErrorCode = 0;
|
||||
mEnv_ShouldAbort = morkBool_kFalse;
|
||||
}
|
||||
|
||||
void
|
||||
morkEnv::AutoClearMorkErrorsAndWarnings()
|
||||
{
|
||||
if ( this->DoAutoClear() )
|
||||
{
|
||||
mEnv_ErrorCount = 0;
|
||||
mEnv_WarningCount = 0;
|
||||
mEnv_ErrorCode = 0;
|
||||
mEnv_ShouldAbort = morkBool_kFalse;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ morkEnv*
|
||||
morkEnv::FromMdbEnv(nsIMdbEnv* ioEnv) // dynamic type checking
|
||||
{
|
||||
morkEnv* outEnv = 0;
|
||||
if ( ioEnv )
|
||||
{
|
||||
// Note this cast is expected to perform some address adjustment of the
|
||||
// pointer, so oenv likely does not equal ioEnv. Do not cast to void*
|
||||
// first to force an exactly equal pointer (we tried it and it's wrong).
|
||||
morkEnv* ev = (morkEnv*) ioEnv;
|
||||
if ( ev && ev->IsEnv() )
|
||||
{
|
||||
if ( ev->DoAutoClear() )
|
||||
{
|
||||
ev->mEnv_ErrorCount = 0;
|
||||
ev->mEnv_WarningCount = 0;
|
||||
ev->mEnv_ErrorCode = 0;
|
||||
}
|
||||
outEnv = ev;
|
||||
}
|
||||
else
|
||||
MORK_ASSERT(outEnv);
|
||||
}
|
||||
else
|
||||
MORK_ASSERT(outEnv);
|
||||
return outEnv;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetErrorCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort)
|
||||
{
|
||||
if ( outCount )
|
||||
*outCount = mEnv_ErrorCount;
|
||||
if ( outShouldAbort )
|
||||
*outShouldAbort = mEnv_ShouldAbort;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort)
|
||||
{
|
||||
if ( outCount )
|
||||
*outCount = mEnv_WarningCount;
|
||||
if ( outShouldAbort )
|
||||
*outShouldAbort = mEnv_ShouldAbort;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetEnvBeVerbose(mdb_bool* outBeVerbose)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outBeVerbose);
|
||||
*outBeVerbose = mEnv_BeVerbose;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::SetEnvBeVerbose(mdb_bool inBeVerbose)
|
||||
{
|
||||
mEnv_BeVerbose = inBeVerbose;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetDoTrace(mdb_bool* outDoTrace)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outDoTrace);
|
||||
*outDoTrace = mEnv_DoTrace;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::SetDoTrace(mdb_bool inDoTrace)
|
||||
{
|
||||
mEnv_DoTrace = inDoTrace;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetAutoClear(mdb_bool* outAutoClear)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outAutoClear);
|
||||
*outAutoClear = DoAutoClear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::SetAutoClear(mdb_bool inAutoClear)
|
||||
{
|
||||
if ( inAutoClear )
|
||||
EnableAutoClear();
|
||||
else
|
||||
DisableAutoClear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetErrorHook(nsIMdbErrorHook** acqErrorHook)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(acqErrorHook);
|
||||
*acqErrorHook = mEnv_ErrorHook;
|
||||
NS_IF_ADDREF(mEnv_ErrorHook);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::SetErrorHook(
|
||||
nsIMdbErrorHook* ioErrorHook) // becomes referenced
|
||||
{
|
||||
mEnv_ErrorHook = ioErrorHook;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::GetHeap(nsIMdbHeap** acqHeap)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(acqHeap);
|
||||
nsIMdbHeap* outHeap = 0;
|
||||
nsIMdbHeap* heap = mEnv_Heap;
|
||||
if ( heap && heap->HeapAddStrongRef(this) == 0 )
|
||||
outHeap = heap;
|
||||
|
||||
if ( acqHeap )
|
||||
*acqHeap = outHeap;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::SetHeap(
|
||||
nsIMdbHeap* ioHeap) // becomes referenced
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioHeap, this, &mEnv_Heap);
|
||||
return NS_OK;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::ClearErrors() // clear errors beore re-entering db API
|
||||
{
|
||||
mEnv_ErrorCount = 0;
|
||||
mEnv_ErrorCode = 0;
|
||||
mEnv_ShouldAbort = morkBool_kFalse;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::ClearWarnings() // clear warning
|
||||
{
|
||||
mEnv_WarningCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkEnv::ClearErrorsAndWarnings() // clear both errors & warnings
|
||||
{
|
||||
ClearMorkErrorsAndWarnings();
|
||||
return NS_OK;
|
||||
}
|
||||
// } ===== end nsIMdbEnv methods =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,243 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#define _MORKENV_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
// sean was here
|
||||
#include "nsError.h"
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kEnv /*i*/ 0x4576 /* ascii 'Ev' */
|
||||
|
||||
// use NS error codes to make Mork easier to use with the rest of mozilla
|
||||
#define morkEnv_kNoError NS_SUCCEEDED /* no error has happened */
|
||||
#define morkEnv_kGenericError NS_ERROR_FAILURE /* non-specific error code */
|
||||
#define morkEnv_kNonEnvTypeError NS_ERROR_FAILURE /* morkEnv::IsEnv() is false */
|
||||
|
||||
#define morkEnv_kStubMethodOnlyError NS_ERROR_NO_INTERFACE
|
||||
#define morkEnv_kOutOfMemoryError NS_ERROR_OUT_OF_MEMORY
|
||||
#define morkEnv_kNilPointerError NS_ERROR_NULL_POINTER
|
||||
#define morkEnv_kNewNonEnvError NS_ERROR_FAILURE
|
||||
#define morkEnv_kNilEnvSlotError NS_ERROR_FAILURE
|
||||
|
||||
#define morkEnv_kBadFactoryError NS_ERROR_FACTORY_NOT_LOADED
|
||||
#define morkEnv_kBadFactoryEnvError NS_ERROR_FACTORY_NOT_LOADED
|
||||
#define morkEnv_kBadEnvError NS_ERROR_FAILURE
|
||||
|
||||
#define morkEnv_kNonHandleTypeError NS_ERROR_FAILURE
|
||||
#define morkEnv_kNonOpenNodeError NS_ERROR_FAILURE
|
||||
|
||||
|
||||
#define morkEnv_kWeakRefCountEnvBonus 0 /* try NOT to leak all env instances */
|
||||
|
||||
/*| morkEnv:
|
||||
|*/
|
||||
class morkEnv : public morkObject, public nsIMdbEnv {
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkFactory* mEnv_Factory; // NON-refcounted factory
|
||||
nsIMdbHeap* mEnv_Heap; // NON-refcounted heap
|
||||
|
||||
nsIMdbEnv* mEnv_SelfAsMdbEnv;
|
||||
nsIMdbErrorHook* mEnv_ErrorHook;
|
||||
|
||||
morkPool* mEnv_HandlePool; // pool for re-using handles
|
||||
|
||||
mork_u2 mEnv_ErrorCount;
|
||||
mork_u2 mEnv_WarningCount;
|
||||
|
||||
mork_u4 mEnv_ErrorCode; // simple basis for mdb_err style errors
|
||||
|
||||
mork_bool mEnv_DoTrace;
|
||||
mork_able mEnv_AutoClear;
|
||||
mork_bool mEnv_ShouldAbort;
|
||||
mork_bool mEnv_BeVerbose;
|
||||
mork_bool mEnv_OwnsHeap;
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseEnv() only if open
|
||||
virtual ~morkEnv(); // assert that CloseEnv() executed earlier
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetErrorCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort);
|
||||
NS_IMETHOD GetWarningCount(mdb_count* outCount,
|
||||
mdb_bool* outShouldAbort);
|
||||
|
||||
NS_IMETHOD GetEnvBeVerbose(mdb_bool* outBeVerbose);
|
||||
NS_IMETHOD SetEnvBeVerbose(mdb_bool inBeVerbose);
|
||||
|
||||
NS_IMETHOD GetDoTrace(mdb_bool* outDoTrace);
|
||||
NS_IMETHOD SetDoTrace(mdb_bool inDoTrace);
|
||||
|
||||
NS_IMETHOD GetAutoClear(mdb_bool* outAutoClear);
|
||||
NS_IMETHOD SetAutoClear(mdb_bool inAutoClear);
|
||||
|
||||
NS_IMETHOD GetErrorHook(nsIMdbErrorHook** acqErrorHook);
|
||||
NS_IMETHOD SetErrorHook(
|
||||
nsIMdbErrorHook* ioErrorHook); // becomes referenced
|
||||
|
||||
NS_IMETHOD GetHeap(nsIMdbHeap** acqHeap);
|
||||
NS_IMETHOD SetHeap(
|
||||
nsIMdbHeap* ioHeap); // becomes referenced
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
NS_IMETHOD ClearErrors(); // clear errors beore re-entering db API
|
||||
NS_IMETHOD ClearWarnings(); // clear warnings
|
||||
NS_IMETHOD ClearErrorsAndWarnings(); // clear both errors & warnings
|
||||
// } ===== end nsIMdbEnv methods =====
|
||||
public: // morkEnv construction & destruction
|
||||
morkEnv(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
morkFactory* ioFactory, nsIMdbHeap* ioSlotHeap);
|
||||
morkEnv(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbEnv* inSelfAsMdbEnv, morkFactory* ioFactory,
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
void CloseEnv(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkEnv(const morkEnv& other);
|
||||
morkEnv& operator=(const morkEnv& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsEnv() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kEnv; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // utility env methods
|
||||
|
||||
mork_u1 HexToByte(mork_ch inFirstHex, mork_ch inSecondHex);
|
||||
|
||||
mork_size TokenAsHex(void* outBuf, mork_token inToken);
|
||||
// TokenAsHex() is the same as sprintf(outBuf, "%lX", (long) inToken);
|
||||
|
||||
mork_size OidAsHex(void* outBuf, const mdbOid& inOid);
|
||||
// sprintf(buf, "%lX:^%lX", (long) inOid.mOid_Id, (long) inOid.mOid_Scope);
|
||||
|
||||
char* CopyString(nsIMdbHeap* ioHeap, const char* inString);
|
||||
void FreeString(nsIMdbHeap* ioHeap, char* ioString);
|
||||
void StringToYarn(const char* inString, mdbYarn* outYarn);
|
||||
|
||||
public: // other env methods
|
||||
|
||||
morkHandleFace* NewHandle(mork_size inSize)
|
||||
{ return mEnv_HandlePool->NewHandle(this, inSize, (morkZone*) 0); }
|
||||
|
||||
void ZapHandle(morkHandleFace* ioHandle)
|
||||
{ mEnv_HandlePool->ZapHandle(this, ioHandle); }
|
||||
|
||||
void EnableAutoClear() { mEnv_AutoClear = morkAble_kEnabled; }
|
||||
void DisableAutoClear() { mEnv_AutoClear = morkAble_kDisabled; }
|
||||
|
||||
mork_bool DoAutoClear() const
|
||||
{ return mEnv_AutoClear == morkAble_kEnabled; }
|
||||
|
||||
void NewErrorAndCode(const char* inString, mork_u2 inCode);
|
||||
void NewError(const char* inString);
|
||||
void NewWarning(const char* inString);
|
||||
|
||||
void ClearMorkErrorsAndWarnings(); // clear both errors & warnings
|
||||
void AutoClearMorkErrorsAndWarnings(); // clear if auto is enabled
|
||||
|
||||
void StubMethodOnlyError();
|
||||
void OutOfMemoryError();
|
||||
void NilPointerError();
|
||||
void NilPointerWarning();
|
||||
void CantMakeWhenBadError();
|
||||
void NewNonEnvError();
|
||||
void NilEnvSlotError();
|
||||
|
||||
void NonEnvTypeError(morkEnv* ev);
|
||||
|
||||
// canonical env convenience methods to check for presence of errors:
|
||||
mork_bool Good() const { return ( mEnv_ErrorCount == 0 ); }
|
||||
mork_bool Bad() const { return ( mEnv_ErrorCount != 0 ); }
|
||||
|
||||
nsIMdbEnv* AsMdbEnv() { return (nsIMdbEnv *) this; }
|
||||
static morkEnv* FromMdbEnv(nsIMdbEnv* ioEnv); // dynamic type checking
|
||||
|
||||
mork_u4 ErrorCode() const { return mEnv_ErrorCode; }
|
||||
|
||||
mdb_err AsErr() const { return (mdb_err) mEnv_ErrorCode; }
|
||||
//mdb_err AsErr() const { return (mdb_err) ( mEnv_ErrorCount != 0 ); }
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakEnv(morkEnv* me,
|
||||
morkEnv* ev, morkEnv** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongEnv(morkEnv* me,
|
||||
morkEnv* ev, morkEnv** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKENV_ */
|
|
@ -0,0 +1,656 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFACTORY_
|
||||
#include "morkFactory.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINHEAP_
|
||||
#include "orkinHeap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTHUMB_
|
||||
#include "morkThumb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKWRITER_
|
||||
#include "morkWriter.h"
|
||||
#endif
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkFactory::CloseMorkNode(morkEnv* ev) /*i*/ // CloseFactory() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseFactory(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkFactory::~morkFactory() /*i*/ // assert CloseFactory() executed earlier
|
||||
{
|
||||
CloseFactory(&mFactory_Env);
|
||||
MORK_ASSERT(mFactory_Env.IsShutNode());
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkFactory::morkFactory() // uses orkinHeap
|
||||
: morkObject(morkUsage::kGlobal, (nsIMdbHeap*) 0, morkColor_kNone)
|
||||
, mFactory_Env(morkUsage::kMember, (nsIMdbHeap*) 0, this,
|
||||
new orkinHeap())
|
||||
, mFactory_Heap()
|
||||
{
|
||||
if ( mFactory_Env.Good() )
|
||||
{
|
||||
mNode_Derived = morkDerived_kFactory;
|
||||
mNode_Refs += morkFactory_kWeakRefCountBonus;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkFactory::morkFactory(nsIMdbHeap* ioHeap)
|
||||
: morkObject(morkUsage::kHeap, ioHeap, morkColor_kNone)
|
||||
, mFactory_Env(morkUsage::kMember, (nsIMdbHeap*) 0, this, ioHeap)
|
||||
, mFactory_Heap()
|
||||
{
|
||||
if ( mFactory_Env.Good() )
|
||||
{
|
||||
mNode_Derived = morkDerived_kFactory;
|
||||
mNode_Refs += morkFactory_kWeakRefCountBonus;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkFactory::morkFactory(morkEnv* ev, /*i*/
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mFactory_Env(morkUsage::kMember, (nsIMdbHeap*) 0, this, ioHeap)
|
||||
, mFactory_Heap()
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mNode_Derived = morkDerived_kFactory;
|
||||
mNode_Refs += morkFactory_kWeakRefCountBonus;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkFactory, morkObject, nsIMdbFactory)
|
||||
|
||||
extern "C" nsIMdbFactory* MakeMdbFactory()
|
||||
{
|
||||
return new morkFactory(new orkinHeap());
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkFactory::CloseFactory(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mFactory_Env.CloseMorkNode(ev);
|
||||
this->CloseObject(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
morkEnv* morkFactory::GetInternalFactoryEnv(mdb_err* outErr)
|
||||
{
|
||||
morkEnv* outEnv = 0;
|
||||
if (IsNode() && IsOpenNode() && IsFactory() )
|
||||
{
|
||||
morkEnv* fenv = &mFactory_Env;
|
||||
if ( fenv && fenv->IsNode() && fenv->IsOpenNode() && fenv->IsEnv() )
|
||||
{
|
||||
fenv->ClearMorkErrorsAndWarnings(); // drop any earlier errors
|
||||
outEnv = fenv;
|
||||
}
|
||||
else
|
||||
*outErr = morkEnv_kBadFactoryEnvError;
|
||||
}
|
||||
else
|
||||
*outErr = morkEnv_kBadFactoryError;
|
||||
|
||||
return outEnv;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
morkFactory::NonFactoryTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkFactory");
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::OpenOldFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath,
|
||||
mork_bool inFrozen, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
morkFile* file = nsnull;
|
||||
if ( ev )
|
||||
{
|
||||
if ( !ioHeap )
|
||||
ioHeap = &mFactory_Heap;
|
||||
|
||||
file = morkFile::OpenOldFile(ev, ioHeap, inFilePath, inFrozen);
|
||||
NS_IF_ADDREF( file );
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = file;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::CreateNewFile(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, nsIMdbFile** acqFile)
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
morkFile* file = nsnull;
|
||||
if ( ev )
|
||||
{
|
||||
if ( !ioHeap )
|
||||
ioHeap = &mFactory_Heap;
|
||||
|
||||
file = morkFile::CreateNewFile(ev, ioHeap, inFilePath);
|
||||
if ( file )
|
||||
NS_ADDREF(file);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqFile )
|
||||
*acqFile = file;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv)
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbEnv* outEnv = 0;
|
||||
mork_bool ownsHeap = (ioHeap == 0);
|
||||
if ( !ioHeap )
|
||||
ioHeap = new orkinHeap();
|
||||
|
||||
if ( acqEnv && ioHeap )
|
||||
{
|
||||
morkEnv* fenv = this->GetInternalFactoryEnv(&outErr);
|
||||
if ( fenv )
|
||||
{
|
||||
morkEnv* newEnv = new(*ioHeap, fenv)
|
||||
morkEnv(morkUsage::kHeap, ioHeap, this, ioHeap);
|
||||
|
||||
if ( newEnv )
|
||||
{
|
||||
newEnv->mEnv_OwnsHeap = ownsHeap;
|
||||
newEnv->mNode_Refs += morkEnv_kWeakRefCountEnvBonus;
|
||||
NS_ADDREF(newEnv);
|
||||
newEnv->mEnv_SelfAsMdbEnv = newEnv;
|
||||
outEnv = newEnv;
|
||||
}
|
||||
else
|
||||
outErr = morkEnv_kOutOfMemoryError;
|
||||
}
|
||||
|
||||
*acqEnv = outEnv;
|
||||
}
|
||||
else
|
||||
outErr = morkEnv_kNilPointerError;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end env methods -----
|
||||
|
||||
// { ----- begin heap methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::MakeHeap(nsIMdbEnv* mev, nsIMdbHeap** acqHeap)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbHeap* outHeap = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
outHeap = new orkinHeap();
|
||||
if ( !outHeap )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
MORK_ASSERT(acqHeap);
|
||||
if ( acqHeap )
|
||||
*acqHeap = outHeap;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end heap methods -----
|
||||
|
||||
// { ----- begin compare methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::MakeCompare(nsIMdbEnv* mev, nsIMdbCompare** acqCompare)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// } ----- end compare methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::MakeRow(nsIMdbEnv* mev, nsIMdbHeap* ioHeap,
|
||||
nsIMdbRow** acqRow)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// ioHeap can be nil, causing the heap associated with ev to be used
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin port methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::CanOpenFilePort(
|
||||
nsIMdbEnv* mev, // context
|
||||
// const char* inFilePath, // the file to investigate
|
||||
// const mdbYarn* inFirst512Bytes,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
mdb_bool* outCanOpen, // whether OpenFilePort() might succeed
|
||||
mdbYarn* outFormatVersion)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
if ( outFormatVersion )
|
||||
{
|
||||
outFormatVersion->mYarn_Fill = 0;
|
||||
}
|
||||
mdb_bool canOpenAsPort = morkBool_kFalse;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( ioFile && outCanOpen )
|
||||
{
|
||||
canOpenAsPort = this->CanOpenMorkTextFile(ev, ioFile);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
if ( outCanOpen )
|
||||
*outCanOpen = canOpenAsPort;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::OpenFilePort(
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // the file to open for readonly import
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbThumb** acqThumb)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "this doesn't look implemented");
|
||||
MORK_USED_1(ioHeap);
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbThumb* outThumb = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( ioFile && inOpenPolicy && acqThumb )
|
||||
{
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqThumb )
|
||||
*acqThumb = outThumb;
|
||||
return outErr;
|
||||
}
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort()
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbThumb* ioThumb, // thumb from OpenFilePort() with done status
|
||||
nsIMdbPort** acqPort)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbPort* outPort = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( ioThumb && acqPort )
|
||||
{
|
||||
morkThumb* thumb = (morkThumb*) ioThumb;
|
||||
morkStore* store = thumb->ThumbToOpenStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
NS_ADDREF(store);
|
||||
outPort = store;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqPort )
|
||||
*acqPort = outPort;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end port methods -----
|
||||
|
||||
mork_bool
|
||||
morkFactory::CanOpenMorkTextFile(morkEnv* ev,
|
||||
// const mdbYarn* inFirst512Bytes,
|
||||
nsIMdbFile* ioFile)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mork_bool outBool = morkBool_kFalse;
|
||||
mork_size headSize = MORK_STRLEN(morkWriter_kFileHeader);
|
||||
|
||||
char localBuf[ 256 + 4 ]; // for extra for sloppy safety
|
||||
mdbYarn localYarn;
|
||||
mdbYarn* y = &localYarn;
|
||||
y->mYarn_Buf = localBuf; // space to hold content
|
||||
y->mYarn_Fill = 0; // no logical content yet
|
||||
y->mYarn_Size = 256; // physical capacity is 256 bytes
|
||||
y->mYarn_More = 0;
|
||||
y->mYarn_Form = 0;
|
||||
y->mYarn_Grow = 0;
|
||||
|
||||
if ( ioFile )
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
mdb_size actualSize = 0;
|
||||
ioFile->Get(menv, y->mYarn_Buf, y->mYarn_Size, /*pos*/ 0, &actualSize);
|
||||
y->mYarn_Fill = actualSize;
|
||||
|
||||
if ( y->mYarn_Buf && actualSize >= headSize && ev->Good() )
|
||||
{
|
||||
mork_u1* buf = (mork_u1*) y->mYarn_Buf;
|
||||
outBool = ( MORK_MEMCMP(morkWriter_kFileHeader, buf, headSize) == 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outBool;
|
||||
}
|
||||
|
||||
// { ----- begin store methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFactory::CanOpenFileStore(
|
||||
nsIMdbEnv* mev, // context
|
||||
// const char* inFilePath, // the file to investigate
|
||||
// const mdbYarn* inFirst512Bytes,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
mdb_bool* outCanOpenAsStore, // whether OpenFileStore() might succeed
|
||||
mdb_bool* outCanOpenAsPort, // whether OpenFilePort() might succeed
|
||||
mdbYarn* outFormatVersion)
|
||||
{
|
||||
mdb_bool canOpenAsStore = morkBool_kFalse;
|
||||
mdb_bool canOpenAsPort = morkBool_kFalse;
|
||||
if ( outFormatVersion )
|
||||
{
|
||||
outFormatVersion->mYarn_Fill = 0;
|
||||
}
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( ioFile && outCanOpenAsStore )
|
||||
{
|
||||
// right now always say true; later we should look for magic patterns
|
||||
canOpenAsStore = this->CanOpenMorkTextFile(ev, ioFile);
|
||||
canOpenAsPort = canOpenAsStore;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outCanOpenAsStore )
|
||||
*outCanOpenAsStore = canOpenAsStore;
|
||||
|
||||
if ( outCanOpenAsPort )
|
||||
*outCanOpenAsPort = canOpenAsPort;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::OpenFileStore( // open an existing database
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // the file to open for general db usage
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbThumb** acqThumb)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbThumb* outThumb = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( !ioHeap ) // need to use heap from env?
|
||||
ioHeap = ev->mEnv_Heap;
|
||||
|
||||
if ( ioFile && inOpenPolicy && acqThumb )
|
||||
{
|
||||
morkStore* store = new(*ioHeap, ev)
|
||||
morkStore(ev, morkUsage::kHeap, ioHeap, this, ioHeap);
|
||||
|
||||
if ( store )
|
||||
{
|
||||
mork_bool frozen = morkBool_kFalse; // open store mutable access
|
||||
if ( store->OpenStoreFile(ev, frozen, ioFile, inOpenPolicy) )
|
||||
{
|
||||
morkThumb* thumb = morkThumb::Make_OpenFileStore(ev, ioHeap, store);
|
||||
if ( thumb )
|
||||
{
|
||||
outThumb = thumb;
|
||||
thumb->AddRef();
|
||||
}
|
||||
}
|
||||
// store->CutStrongRef(mev); // always cut ref (handle has its own ref)
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqThumb )
|
||||
*acqThumb = outThumb;
|
||||
return outErr;
|
||||
}
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbThumb* ioThumb, // thumb from OpenFileStore() with done status
|
||||
nsIMdbStore** acqStore)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbStore* outStore = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( ioThumb && acqStore )
|
||||
{
|
||||
morkThumb* thumb = (morkThumb*) ioThumb;
|
||||
morkStore* store = thumb->ThumbToOpenStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
outStore = store;
|
||||
NS_ADDREF(store);
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqStore )
|
||||
*acqStore = outStore;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFactory::CreateNewFileStore( // create a new db with minimal content
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // name of file which should not yet exist
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbStore** acqStore)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbStore* outStore = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( !ioHeap ) // need to use heap from env?
|
||||
ioHeap = ev->mEnv_Heap;
|
||||
|
||||
if ( ioFile && inOpenPolicy && acqStore && ioHeap )
|
||||
{
|
||||
morkStore* store = new(*ioHeap, ev)
|
||||
morkStore(ev, morkUsage::kHeap, ioHeap, this, ioHeap);
|
||||
|
||||
if ( store )
|
||||
{
|
||||
store->mStore_CanAutoAssignAtomIdentity = morkBool_kTrue;
|
||||
store->mStore_CanDirty = morkBool_kTrue;
|
||||
store->SetStoreAndAllSpacesCanDirty(ev, morkBool_kTrue);
|
||||
|
||||
if ( store->CreateStoreFile(ev, ioFile, inOpenPolicy) )
|
||||
outStore = store;
|
||||
NS_ADDREF(store);
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqStore )
|
||||
*acqStore = outStore;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end store methods -----
|
||||
|
||||
// } ===== end nsIMdbFactory methods =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,239 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKFACTORY_
|
||||
#define _MORKFACTORY_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINHEAP_
|
||||
#include "orkinHeap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbFactory;
|
||||
|
||||
#define morkDerived_kFactory /*i*/ 0x4663 /* ascii 'Fc' */
|
||||
#define morkFactory_kWeakRefCountBonus 0 /* try NOT to leak all factories */
|
||||
|
||||
/*| morkFactory:
|
||||
|*/
|
||||
class morkFactory : public morkObject, public nsIMdbFactory { // nsIMdbObject
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkEnv mFactory_Env; // private env instance used internally
|
||||
orkinHeap mFactory_Heap;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkFactory virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseFactory() only if open
|
||||
virtual ~morkFactory(); // assert that CloseFactory() executed earlier
|
||||
|
||||
|
||||
// { ===== begin nsIMdbFactory methods =====
|
||||
|
||||
// { ----- begin file methods -----
|
||||
NS_IMETHOD OpenOldFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath,
|
||||
mdb_bool inFrozen, nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
NS_IMETHOD CreateNewFile(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath,
|
||||
nsIMdbFile** acqFile);
|
||||
// Choose some subclass of nsIMdbFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
// } ----- end file methods -----
|
||||
|
||||
// { ----- begin env methods -----
|
||||
NS_IMETHOD MakeEnv(nsIMdbHeap* ioHeap, nsIMdbEnv** acqEnv); // new env
|
||||
// ioHeap can be nil, causing a MakeHeap() style heap instance to be used
|
||||
// } ----- end env methods -----
|
||||
|
||||
// { ----- begin heap methods -----
|
||||
NS_IMETHOD MakeHeap(nsIMdbEnv* ev, nsIMdbHeap** acqHeap); // new heap
|
||||
// } ----- end heap methods -----
|
||||
|
||||
// { ----- begin compare methods -----
|
||||
NS_IMETHOD MakeCompare(nsIMdbEnv* ev, nsIMdbCompare** acqCompare); // ASCII
|
||||
// } ----- end compare methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHOD MakeRow(nsIMdbEnv* ev, nsIMdbHeap* ioHeap, nsIMdbRow** acqRow); // new row
|
||||
// ioHeap can be nil, causing the heap associated with ev to be used
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin port methods -----
|
||||
NS_IMETHOD CanOpenFilePort(
|
||||
nsIMdbEnv* ev, // context
|
||||
// const char* inFilePath, // the file to investigate
|
||||
// const mdbYarn* inFirst512Bytes,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
mdb_bool* outCanOpen, // whether OpenFilePort() might succeed
|
||||
mdbYarn* outFormatVersion); // informal file format description
|
||||
|
||||
NS_IMETHOD OpenFilePort(
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // the file to open for readonly import
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental port open
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then call nsIMdbFactory::ThumbToOpenPort() to get the port instance.
|
||||
|
||||
NS_IMETHOD ThumbToOpenPort( // redeeming a completed thumb from OpenFilePort()
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbThumb* ioThumb, // thumb from OpenFilePort() with done status
|
||||
nsIMdbPort** acqPort); // acquire new port object
|
||||
// } ----- end port methods -----
|
||||
|
||||
// { ----- begin store methods -----
|
||||
NS_IMETHOD CanOpenFileStore(
|
||||
nsIMdbEnv* ev, // context
|
||||
// const char* inFilePath, // the file to investigate
|
||||
// const mdbYarn* inFirst512Bytes,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
mdb_bool* outCanOpenAsStore, // whether OpenFileStore() might succeed
|
||||
mdb_bool* outCanOpenAsPort, // whether OpenFilePort() might succeed
|
||||
mdbYarn* outFormatVersion); // informal file format description
|
||||
|
||||
NS_IMETHOD OpenFileStore( // open an existing database
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // the file to open for general db usage
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental store open
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then call nsIMdbFactory::ThumbToOpenStore() to get the store instance.
|
||||
|
||||
NS_IMETHOD
|
||||
ThumbToOpenStore( // redeem completed thumb from OpenFileStore()
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbThumb* ioThumb, // thumb from OpenFileStore() with done status
|
||||
nsIMdbStore** acqStore); // acquire new db store object
|
||||
|
||||
NS_IMETHOD CreateNewFileStore( // create a new db with minimal content
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbHeap* ioHeap, // can be nil to cause ev's heap attribute to be used
|
||||
// const char* inFilePath, // name of file which should not yet exist
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy, // runtime policies for using db
|
||||
nsIMdbStore** acqStore); // acquire new db store object
|
||||
// } ----- end store methods -----
|
||||
|
||||
// } ===== end nsIMdbFactory methods =====
|
||||
|
||||
public: // morkYarn construction & destruction
|
||||
morkFactory(); // uses orkinHeap
|
||||
morkFactory(nsIMdbHeap* ioHeap); // caller supplied heap
|
||||
morkFactory(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
|
||||
void CloseFactory(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize) CPP_THROW_NEW
|
||||
{ return ::operator new(inSize); }
|
||||
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
private: // copying is not allowed
|
||||
morkFactory(const morkFactory& other);
|
||||
morkFactory& operator=(const morkFactory& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsFactory() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kFactory; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // other factory methods
|
||||
|
||||
void NonFactoryTypeError(morkEnv* ev);
|
||||
morkEnv* GetInternalFactoryEnv(mdb_err* outErr);
|
||||
mork_bool CanOpenMorkTextFile(morkEnv* ev, nsIMdbFile* ioFile);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakFactory(morkFactory* me,
|
||||
morkEnv* ev, morkFactory** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongFactory(morkFactory* me,
|
||||
morkEnv* ev, morkFactory** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKFACTORY_ */
|
|
@ -0,0 +1,926 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
#ifdef MORK_WIN
|
||||
#include "io.h"
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkFile::CloseMorkNode(morkEnv* ev) // CloseFile() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseFile(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkFile::~morkFile() // assert CloseFile() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mFile_Frozen==0);
|
||||
MORK_ASSERT(mFile_DoTrace==0);
|
||||
MORK_ASSERT(mFile_IoOpen==0);
|
||||
MORK_ASSERT(mFile_Active==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkFile::morkFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mFile_Frozen( 0 )
|
||||
, mFile_DoTrace( 0 )
|
||||
, mFile_IoOpen( 0 )
|
||||
, mFile_Active( 0 )
|
||||
|
||||
, mFile_SlotHeap( 0 )
|
||||
, mFile_Name( 0 )
|
||||
, mFile_Thief( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mFile_SlotHeap);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kFile;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkFile, morkObject, nsIMdbFile)
|
||||
/*public non-poly*/ void
|
||||
morkFile::CloseFile(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mFile_Frozen = 0;
|
||||
mFile_DoTrace = 0;
|
||||
mFile_IoOpen = 0;
|
||||
mFile_Active = 0;
|
||||
|
||||
if ( mFile_Name )
|
||||
this->SetFileName(ev, (const char*) 0);
|
||||
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mFile_SlotHeap);
|
||||
nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mFile_Thief);
|
||||
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ morkFile*
|
||||
morkFile::OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen)
|
||||
// Choose some subclass of morkFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
return morkStdioFile::OpenOldStdioFile(ev, ioHeap, inFilePath, inFrozen);
|
||||
}
|
||||
|
||||
/*static*/ morkFile*
|
||||
morkFile::CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath)
|
||||
// Choose some subclass of morkFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
{
|
||||
return morkStdioFile::CreateNewStdioFile(ev, ioHeap, inFilePath);
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::NewMissingIoError(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("file missing io");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NonFileTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkFile");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NilSlotHeapError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mFile_SlotHeap");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkFile::NilFileNameError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mFile_Name");
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetThief(morkEnv* ev, nsIMdbFile* ioThief)
|
||||
{
|
||||
nsIMdbFile_SlotStrongFile(ioThief, ev, &mFile_Thief);
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::SetFileName(morkEnv* ev, const char* inName) // inName can be nil
|
||||
{
|
||||
nsIMdbHeap* heap = mFile_SlotHeap;
|
||||
if ( heap )
|
||||
{
|
||||
char* name = mFile_Name;
|
||||
if ( name )
|
||||
{
|
||||
mFile_Name = 0;
|
||||
ev->FreeString(heap, name);
|
||||
}
|
||||
if ( ev->Good() && inName )
|
||||
mFile_Name = ev->CopyString(heap, inName);
|
||||
}
|
||||
else
|
||||
this->NilSlotHeapError(ev);
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::NewFileDownError(morkEnv* ev) const
|
||||
// call NewFileDownError() when either IsOpenAndActiveFile()
|
||||
// is false, or when IsOpenActiveAndMutableFile() is false.
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
if ( this->FileActive() )
|
||||
{
|
||||
if ( this->FileFrozen() )
|
||||
{
|
||||
ev->NewError("file frozen");
|
||||
}
|
||||
else
|
||||
ev->NewError("unknown file problem");
|
||||
}
|
||||
else
|
||||
ev->NewError("file not active");
|
||||
}
|
||||
else
|
||||
ev->NewError("file not open");
|
||||
}
|
||||
|
||||
void
|
||||
morkFile::NewFileErrnoError(morkEnv* ev) const
|
||||
// call NewFileErrnoError() to convert std C errno into AB fault
|
||||
{
|
||||
const char* errnoString = strerror(errno);
|
||||
ev->NewError(errnoString); // maybe pass value of strerror() instead
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` newlines ````` ````` ````` `````
|
||||
|
||||
#if defined(MORK_MAC)
|
||||
static const char morkFile_kNewlines[] =
|
||||
"\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015";
|
||||
# define morkFile_kNewlinesCount 16
|
||||
#else
|
||||
# if defined(MORK_WIN) || defined(MORK_OS2)
|
||||
static const char morkFile_kNewlines[] =
|
||||
"\015\012\015\012\015\012\015\012\015\012\015\012\015\012\015\012";
|
||||
# define morkFile_kNewlinesCount 8
|
||||
# else
|
||||
# ifdef MORK_UNIX
|
||||
static const char morkFile_kNewlines[] =
|
||||
"\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012";
|
||||
# define morkFile_kNewlinesCount 16
|
||||
# endif /* MORK_UNIX */
|
||||
# endif /* MORK_WIN */
|
||||
#endif /* MORK_MAC */
|
||||
|
||||
mork_size
|
||||
morkFile::WriteNewlines(morkEnv* ev, mork_count inNewlines)
|
||||
// WriteNewlines() returns the number of bytes written.
|
||||
{
|
||||
mork_size outSize = 0;
|
||||
while ( inNewlines && ev->Good() ) // more newlines to write?
|
||||
{
|
||||
mork_u4 quantum = inNewlines;
|
||||
if ( quantum > morkFile_kNewlinesCount )
|
||||
quantum = morkFile_kNewlinesCount;
|
||||
|
||||
mork_size quantumSize = quantum * mork_kNewlineSize;
|
||||
mdb_size bytesWritten;
|
||||
this->Write(ev->AsMdbEnv(), morkFile_kNewlines, quantumSize, &bytesWritten);
|
||||
outSize += quantumSize;
|
||||
inNewlines -= quantum;
|
||||
}
|
||||
return outSize;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFile::Eof(nsIMdbEnv* mev, mdb_pos* outPos)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_pos pos = -1;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
pos = Length(ev);
|
||||
outErr = ev->AsErr();
|
||||
if ( outPos )
|
||||
*outPos = pos;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFile::Get(nsIMdbEnv* mev, void* outBuf, mdb_size inSize,
|
||||
mdb_pos inPos, mdb_size* outActualSize)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
mdb_pos outPos;
|
||||
Seek(mev, inPos, &outPos);
|
||||
if ( ev->Good() )
|
||||
rv = Read(mev, outBuf, inSize, outActualSize);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFile::Put(nsIMdbEnv* mev, const void* inBuf, mdb_size inSize,
|
||||
mdb_pos inPos, mdb_size* outActualSize)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
*outActualSize = 0;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
mdb_pos outPos;
|
||||
|
||||
Seek(mev, inPos, &outPos);
|
||||
if ( ev->Good() )
|
||||
Write(mev, inBuf, inSize, outActualSize);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
// { ----- begin path methods -----
|
||||
NS_IMETHODIMP
|
||||
morkFile::Path(nsIMdbEnv* mev, mdbYarn* outFilePath)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
if ( outFilePath )
|
||||
outFilePath->mYarn_Fill = 0;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
ev->StringToYarn(GetFileNameString(), outFilePath);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end path methods -----
|
||||
|
||||
// { ----- begin replacement methods -----
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkFile::Thief(nsIMdbEnv* mev, nsIMdbFile** acqThief)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFile* outThief = 0;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
outThief = GetThief();
|
||||
NS_IF_ADDREF(outThief);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqThief )
|
||||
*acqThief = outThief;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end replacement methods -----
|
||||
|
||||
// { ----- begin versioning methods -----
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStdioFile::CloseMorkNode(morkEnv* ev) // CloseStdioFile() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseStdioFile(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkStdioFile::~morkStdioFile() // assert CloseStdioFile() executed earlier
|
||||
{
|
||||
if (mStdioFile_File)
|
||||
CloseStdioFile(mMorkEnv);
|
||||
MORK_ASSERT(mStdioFile_File==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkStdioFile::CloseStdioFile(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
|
||||
{
|
||||
this->CloseStdio(ev);
|
||||
}
|
||||
|
||||
mStdioFile_File = 0;
|
||||
|
||||
this->CloseFile(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
// compatible with the morkFile::MakeFile() entry point
|
||||
|
||||
/*static*/ morkStdioFile*
|
||||
morkStdioFile::OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen)
|
||||
{
|
||||
morkStdioFile* outFile = 0;
|
||||
if ( ioHeap && inFilePath )
|
||||
{
|
||||
const char* mode = (inFrozen)? "rb" : "rb+";
|
||||
outFile = new(*ioHeap, ev)
|
||||
morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
|
||||
|
||||
if ( outFile )
|
||||
{
|
||||
outFile->SetFileFrozen(inFrozen);
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
/*static*/ morkStdioFile*
|
||||
morkStdioFile::CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath)
|
||||
{
|
||||
morkStdioFile* outFile = 0;
|
||||
if ( ioHeap && inFilePath )
|
||||
{
|
||||
const char* mode = "wb+";
|
||||
outFile = new(*ioHeap, ev)
|
||||
morkStdioFile(ev, morkUsage::kHeap, ioHeap, ioHeap, inFilePath, mode);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outFile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::BecomeTrunk(nsIMdbEnv* ev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
{
|
||||
return Flush(ev);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::AcquireBud(nsIMdbEnv * mdbev, nsIMdbHeap* ioHeap, nsIMdbFile **acquiredFile)
|
||||
// AcquireBud() starts a new "branch" version of the file, empty of content,
|
||||
// so that a new version of the file can be written. This new file
|
||||
// can later be told to BecomeTrunk() the original file, so the branch
|
||||
// created by budding the file will replace the original file. Some
|
||||
// file subclasses might initially take the unsafe but expedient
|
||||
// approach of simply truncating this file down to zero length, and
|
||||
// then returning the same morkFile pointer as this, with an extra
|
||||
// reference count increment. Note that the caller of AcquireBud() is
|
||||
// expected to eventually call CutStrongRef() on the returned file
|
||||
// in order to release the strong reference. High quality versions
|
||||
// of morkFile subclasses will create entirely new files which later
|
||||
// are renamed to become the old file, so that better transactional
|
||||
// behavior is exhibited by the file, so crashes protect old files.
|
||||
// Note that AcquireBud() is an illegal operation on readonly files.
|
||||
{
|
||||
NS_ENSURE_ARG(acquiredFile);
|
||||
MORK_USED_1(ioHeap);
|
||||
nsresult rv = NS_OK;
|
||||
morkFile* outFile = 0;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
|
||||
if ( this->IsOpenAndActiveFile() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
//#ifdef MORK_WIN
|
||||
// truncate(file, /*eof*/ 0);
|
||||
//#else /*MORK_WIN*/
|
||||
char* name = mFile_Name;
|
||||
if ( name )
|
||||
{
|
||||
if ( MORK_FILECLOSE(file) >= 0 )
|
||||
{
|
||||
this->SetFileActive(morkBool_kFalse);
|
||||
this->SetFileIoOpen(morkBool_kFalse);
|
||||
mStdioFile_File = 0;
|
||||
|
||||
file = MORK_FILEOPEN(name, "wb+"); // open for write, discarding old content
|
||||
if ( file )
|
||||
{
|
||||
mStdioFile_File = file;
|
||||
this->SetFileActive(morkBool_kTrue);
|
||||
this->SetFileIoOpen(morkBool_kTrue);
|
||||
this->SetFileFrozen(morkBool_kFalse);
|
||||
}
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else
|
||||
this->NilFileNameError(ev);
|
||||
|
||||
//#endif /*MORK_WIN*/
|
||||
|
||||
if ( ev->Good() && this->AddStrongRef(ev->AsMdbEnv()) )
|
||||
{
|
||||
outFile = this;
|
||||
AddRef();
|
||||
}
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
{
|
||||
rv = mFile_Thief->AcquireBud(ev->AsMdbEnv(), ioHeap, acquiredFile);
|
||||
}
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
*acquiredFile = outFile;
|
||||
return rv;
|
||||
}
|
||||
|
||||
mork_pos
|
||||
morkStdioFile::Length(morkEnv * ev) const
|
||||
{
|
||||
mork_pos outPos = 0;
|
||||
|
||||
if ( this->IsOpenAndActiveFile() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
long start = MORK_FILETELL(file);
|
||||
if ( start >= 0 )
|
||||
{
|
||||
long fore = MORK_FILESEEK(file, 0, SEEK_END);
|
||||
if ( fore >= 0 )
|
||||
{
|
||||
long eof = MORK_FILETELL(file);
|
||||
if ( eof >= 0 )
|
||||
{
|
||||
long back = MORK_FILESEEK(file, start, SEEK_SET);
|
||||
if ( back >= 0 )
|
||||
outPos = eof;
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Eof(ev->AsMdbEnv(), &outPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
return outPos;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Tell(nsIMdbEnv* ev, mork_pos *outPos) const
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
NS_ENSURE_ARG(outPos);
|
||||
morkEnv* mev = morkEnv::FromMdbEnv(ev);
|
||||
if ( this->IsOpenAndActiveFile() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
long where = MORK_FILETELL(file);
|
||||
if ( where >= 0 )
|
||||
*outPos = where;
|
||||
else
|
||||
this->new_stdio_file_fault(mev);
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Tell(ev, outPos);
|
||||
else
|
||||
this->NewMissingIoError(mev);
|
||||
}
|
||||
else this->NewFileDownError(mev);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize, mork_num *outCount)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
morkEnv* mev = morkEnv::FromMdbEnv(ev);
|
||||
if ( this->IsOpenAndActiveFile() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
long count = (long) MORK_FILEREAD(outBuf, inSize, file);
|
||||
if ( count >= 0 )
|
||||
{
|
||||
*outCount = (mork_num) count;
|
||||
}
|
||||
else this->new_stdio_file_fault(mev);
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Read(ev, outBuf, inSize, outCount);
|
||||
else
|
||||
this->NewMissingIoError(mev);
|
||||
}
|
||||
else this->NewFileDownError(mev);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Seek(nsIMdbEnv* mdbev, mork_pos inPos, mork_pos *aOutPos)
|
||||
{
|
||||
mork_pos outPos = 0;
|
||||
nsresult rv = NS_OK;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
|
||||
if ( this->IsOpenOrClosingNode() && this->FileActive() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
long where = MORK_FILESEEK(file, inPos, SEEK_SET);
|
||||
if ( where >= 0 )
|
||||
outPos = inPos;
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Seek(mdbev, inPos, aOutPos);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
*aOutPos = outPos;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Write(nsIMdbEnv* mdbev, const void* inBuf, mork_size inSize, mork_size *aOutSize)
|
||||
{
|
||||
mork_num outCount = 0;
|
||||
nsresult rv = NS_OK;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
if ( this->IsOpenActiveAndMutableFile() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
fwrite(inBuf, 1, inSize, file);
|
||||
if ( !ferror(file) )
|
||||
outCount = inSize;
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Write(mdbev, inBuf, inSize, &outCount);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
*aOutSize = outCount;
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Flush(nsIMdbEnv* mdbev)
|
||||
{
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
if ( this->IsOpenOrClosingNode() && this->FileActive() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( file )
|
||||
{
|
||||
MORK_FILEFLUSH(file);
|
||||
|
||||
}
|
||||
else if ( mFile_Thief )
|
||||
mFile_Thief->Flush(mdbev);
|
||||
else
|
||||
this->NewMissingIoError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
//protected: // protected non-poly morkStdioFile methods
|
||||
|
||||
void
|
||||
morkStdioFile::new_stdio_file_fault(morkEnv* ev) const
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
|
||||
int copyErrno = errno; // facilitate seeing error in debugger
|
||||
|
||||
// bunch of stuff not ported here
|
||||
if ( !copyErrno && file )
|
||||
{
|
||||
copyErrno = ferror(file);
|
||||
errno = copyErrno;
|
||||
}
|
||||
|
||||
this->NewFileErrnoError(ev);
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
//public: // public non-poly morkStdioFile methods
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkStdioFile::morkStdioFile(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
|
||||
, mStdioFile_File( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kStdioFile;
|
||||
}
|
||||
|
||||
morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
|
||||
const char* inName, const char* inMode)
|
||||
// calls OpenStdio() after construction
|
||||
: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
|
||||
, mStdioFile_File( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
this->OpenStdio(ev, inName, inMode);
|
||||
}
|
||||
|
||||
morkStdioFile::morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
|
||||
void* ioFile, const char* inName, mork_bool inFrozen)
|
||||
// calls UseStdio() after construction
|
||||
: morkFile(ev, inUsage, ioHeap, ioSlotHeap)
|
||||
, mStdioFile_File( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
this->UseStdio(ev, ioFile, inName, inFrozen);
|
||||
}
|
||||
|
||||
void
|
||||
morkStdioFile::OpenStdio(morkEnv* ev, const char* inName, const char* inMode)
|
||||
// Open a new FILE with name inName, using mode flags from inMode.
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( !inMode )
|
||||
inMode = "";
|
||||
|
||||
mork_bool frozen = (*inMode == 'r'); // cursory attempt to note readonly
|
||||
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
if ( !this->FileActive() )
|
||||
{
|
||||
this->SetFileIoOpen(morkBool_kFalse);
|
||||
if ( inName && *inName )
|
||||
{
|
||||
this->SetFileName(ev, inName);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
FILE* file = MORK_FILEOPEN(inName, inMode);
|
||||
if ( file )
|
||||
{
|
||||
mStdioFile_File = file;
|
||||
this->SetFileActive(morkBool_kTrue);
|
||||
this->SetFileIoOpen(morkBool_kTrue);
|
||||
this->SetFileFrozen(frozen);
|
||||
}
|
||||
else
|
||||
this->new_stdio_file_fault(ev);
|
||||
}
|
||||
}
|
||||
else ev->NewError("no file name");
|
||||
}
|
||||
else ev->NewError("file already active");
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkStdioFile::UseStdio(morkEnv* ev, void* ioFile, const char* inName,
|
||||
mork_bool inFrozen)
|
||||
// Use an existing file, like stdin/stdout/stderr, which should not
|
||||
// have the io stream closed when the file is closed. The ioFile
|
||||
// parameter must actually be of type FILE (but we don't want to make
|
||||
// this header file include the stdio.h header file).
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
if ( !this->FileActive() )
|
||||
{
|
||||
if ( ioFile )
|
||||
{
|
||||
this->SetFileIoOpen(morkBool_kFalse);
|
||||
this->SetFileName(ev, inName);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mStdioFile_File = ioFile;
|
||||
this->SetFileActive(morkBool_kTrue);
|
||||
this->SetFileFrozen(inFrozen);
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
else ev->NewError("file already active");
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkStdioFile::CloseStdio(morkEnv* ev)
|
||||
// Close the stream io if both and FileActive() and FileIoOpen(), but
|
||||
// this does not close this instances (like CloseStdioFile() does).
|
||||
// If stream io was made active by means of calling UseStdio(),
|
||||
// then this method does little beyond marking the stream inactive
|
||||
// because FileIoOpen() is false.
|
||||
{
|
||||
if ( mStdioFile_File && this->FileActive() && this->FileIoOpen() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( MORK_FILECLOSE(file) < 0 )
|
||||
this->new_stdio_file_fault(ev);
|
||||
|
||||
mStdioFile_File = 0;
|
||||
this->SetFileActive(morkBool_kFalse);
|
||||
this->SetFileIoOpen(morkBool_kFalse);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStdioFile::Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
{
|
||||
morkEnv *mev = morkEnv::FromMdbEnv(ev);
|
||||
if ( mStdioFile_File && FileActive() && FileIoOpen() )
|
||||
{
|
||||
FILE* file = (FILE*) mStdioFile_File;
|
||||
if ( MORK_FILECLOSE(file) < 0 )
|
||||
new_stdio_file_fault(mev);
|
||||
|
||||
mStdioFile_File = 0;
|
||||
}
|
||||
SetThief(mev, ioThief);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
#if defined(MORK_WIN)
|
||||
|
||||
void mork_fileflush(FILE * file)
|
||||
{
|
||||
fflush(file);
|
||||
#ifndef WINCE
|
||||
OSVERSIONINFOA vi = { sizeof(OSVERSIONINFOA) };
|
||||
if ((GetVersionExA(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS))
|
||||
{
|
||||
// Win9x/ME
|
||||
int fd = fileno(file);
|
||||
HANDLE fh = (HANDLE)_get_osfhandle(fd);
|
||||
FlushFileBuffers(fh);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /*MORK_WIN*/
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,356 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#define _MORKFILE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*=============================================================================
|
||||
* morkFile: abstract file interface
|
||||
*/
|
||||
|
||||
#define morkDerived_kFile /*i*/ 0x4669 /* ascii 'Fi' */
|
||||
|
||||
class morkFile /*d*/ : public morkObject, public nsIMdbFile { /* ````` simple file API ````` */
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkFile members (similar to public domain IronDoc)
|
||||
|
||||
mork_u1 mFile_Frozen; // 'F' => file allows only read access
|
||||
mork_u1 mFile_DoTrace; // 'T' trace if ev->DoTrace()
|
||||
mork_u1 mFile_IoOpen; // 'O' => io stream is open (& needs a close)
|
||||
mork_u1 mFile_Active; // 'A' => file is active and usable
|
||||
|
||||
nsIMdbHeap* mFile_SlotHeap; // heap for Name and other allocated slots
|
||||
char* mFile_Name; // can be nil if SetFileName() is never called
|
||||
// mFile_Name convention: managed with morkEnv::CopyString()/FreeString()
|
||||
|
||||
nsIMdbFile* mFile_Thief; // from a call to orkinFile::Steal()
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseFile() only if open
|
||||
virtual ~morkFile(); // assert that CloseFile() executed earlier
|
||||
|
||||
public: // morkFile construction & destruction
|
||||
morkFile(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
void CloseFile(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkFile(const morkFile& other);
|
||||
morkFile& operator=(const morkFile& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsFile() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kFile; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public static standard file creation entry point
|
||||
|
||||
static morkFile* OpenOldFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen);
|
||||
// Choose some subclass of morkFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be open and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
static morkFile* CreateNewFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath);
|
||||
// Choose some subclass of morkFile to instantiate, in order to read
|
||||
// (and write if not frozen) the file known by inFilePath. The file
|
||||
// returned should be created and ready for use, and presumably positioned
|
||||
// at the first byte position of the file. The exact manner in which
|
||||
// files must be opened is considered a subclass specific detail, and
|
||||
// other portions or Mork source code don't want to know how it's done.
|
||||
|
||||
public: // non-poly morkFile methods
|
||||
|
||||
mork_bool FileFrozen() const { return mFile_Frozen == 'F'; }
|
||||
mork_bool FileDoTrace() const { return mFile_DoTrace == 'T'; }
|
||||
mork_bool FileIoOpen() const { return mFile_IoOpen == 'O'; }
|
||||
mork_bool FileActive() const { return mFile_Active == 'A'; }
|
||||
|
||||
void SetFileFrozen(mork_bool b) { mFile_Frozen = (mork_u1) ((b)? 'F' : 0); }
|
||||
void SetFileDoTrace(mork_bool b) { mFile_DoTrace = (mork_u1) ((b)? 'T' : 0); }
|
||||
void SetFileIoOpen(mork_bool b) { mFile_IoOpen = (mork_u1) ((b)? 'O' : 0); }
|
||||
void SetFileActive(mork_bool b) { mFile_Active = (mork_u1) ((b)? 'A' : 0); }
|
||||
|
||||
|
||||
mork_bool IsOpenActiveAndMutableFile() const
|
||||
{ return ( IsOpenNode() && FileActive() && !FileFrozen() ); }
|
||||
// call IsOpenActiveAndMutableFile() before writing a file
|
||||
|
||||
mork_bool IsOpenAndActiveFile() const
|
||||
{ return ( this->IsOpenNode() && this->FileActive() ); }
|
||||
// call IsOpenAndActiveFile() before using a file
|
||||
|
||||
|
||||
nsIMdbFile* GetThief() const { return mFile_Thief; }
|
||||
void SetThief(morkEnv* ev, nsIMdbFile* ioThief); // ioThief can be nil
|
||||
|
||||
const char* GetFileNameString() const { return mFile_Name; }
|
||||
void SetFileName(morkEnv* ev, const char* inName); // inName can be nil
|
||||
static void NilSlotHeapError(morkEnv* ev);
|
||||
static void NilFileNameError(morkEnv* ev);
|
||||
static void NonFileTypeError(morkEnv* ev);
|
||||
|
||||
void NewMissingIoError(morkEnv* ev) const;
|
||||
|
||||
void NewFileDownError(morkEnv* ev) const;
|
||||
// call NewFileDownError() when either IsOpenAndActiveFile()
|
||||
// is false, or when IsOpenActiveAndMutableFile() is false.
|
||||
|
||||
void NewFileErrnoError(morkEnv* ev) const;
|
||||
// call NewFileErrnoError() to convert std C errno into AB fault
|
||||
|
||||
mork_size WriteNewlines(morkEnv* ev, mork_count inNewlines);
|
||||
// WriteNewlines() returns the number of bytes written.
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakFile(morkFile* me,
|
||||
morkEnv* ev, morkFile** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongFile(morkFile* me,
|
||||
morkEnv* ev, morkFile** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
public:
|
||||
virtual mork_pos Length(morkEnv* ev) const = 0; // eof
|
||||
// nsIMdbFile methods
|
||||
NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const = 0;
|
||||
NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos *outPos) = 0;
|
||||
NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos);
|
||||
// } ----- end pos methods -----
|
||||
|
||||
// { ----- begin read methods -----
|
||||
NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
|
||||
mdb_size* outActualSize) = 0;
|
||||
NS_IMETHOD Get(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
|
||||
mdb_pos inPos, mdb_size* outActualSize);
|
||||
// } ----- end read methods -----
|
||||
|
||||
// { ----- begin write methods -----
|
||||
NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
|
||||
mdb_size* outActualSize) = 0;
|
||||
NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
|
||||
mdb_pos inPos, mdb_size* outActualSize);
|
||||
NS_IMETHOD Flush(nsIMdbEnv* ev) = 0;
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin path methods -----
|
||||
NS_IMETHOD Path(nsIMdbEnv* ev, mdbYarn* outFilePath);
|
||||
// } ----- end path methods -----
|
||||
|
||||
// { ----- begin replacement methods -----
|
||||
NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief) = 0;
|
||||
NS_IMETHOD Thief(nsIMdbEnv* ev, nsIMdbFile** acqThief);
|
||||
// } ----- end replacement methods -----
|
||||
|
||||
// { ----- begin versioning methods -----
|
||||
NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev) = 0;
|
||||
|
||||
NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile** acqBud) = 0;
|
||||
// } ----- end versioning methods -----
|
||||
|
||||
// } ===== end nsIMdbFile methods =====
|
||||
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkStdioFile: concrete file using standard C file io
|
||||
*/
|
||||
|
||||
#define morkDerived_kStdioFile /*i*/ 0x7346 /* ascii 'sF' */
|
||||
|
||||
class morkStdioFile /*d*/ : public morkFile { /* `` copied from IronDoc `` */
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkStdioFile members
|
||||
|
||||
void* mStdioFile_File;
|
||||
// actually type FILE*, but using opaque void* type
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseStdioFile() only if open
|
||||
virtual ~morkStdioFile(); // assert that CloseStdioFile() executed earlier
|
||||
|
||||
public: // morkStdioFile construction & destruction
|
||||
morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseStdioFile(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkStdioFile(const morkStdioFile& other);
|
||||
morkStdioFile& operator=(const morkStdioFile& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsStdioFile() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kStdioFile; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonStdioFileTypeError(morkEnv* ev);
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // compatible with the morkFile::OpenOldFile() entry point
|
||||
|
||||
static morkStdioFile* OpenOldStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath, mork_bool inFrozen);
|
||||
|
||||
static morkStdioFile* CreateNewStdioFile(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
const char* inFilePath);
|
||||
|
||||
virtual mork_pos Length(morkEnv* ev) const; // eof
|
||||
|
||||
NS_IMETHOD Tell(nsIMdbEnv* ev, mdb_pos* outPos) const;
|
||||
NS_IMETHOD Seek(nsIMdbEnv* ev, mdb_pos inPos, mdb_pos *outPos);
|
||||
// NS_IMETHOD Eof(nsIMdbEnv* ev, mdb_pos* outPos);
|
||||
// } ----- end pos methods -----
|
||||
|
||||
// { ----- begin read methods -----
|
||||
NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mdb_size inSize,
|
||||
mdb_size* outActualSize);
|
||||
|
||||
// { ----- begin write methods -----
|
||||
NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
|
||||
mdb_size* outActualSize);
|
||||
// NS_IMETHOD Put(nsIMdbEnv* ev, const void* inBuf, mdb_size inSize,
|
||||
// mdb_pos inPos, mdb_size* outActualSize);
|
||||
NS_IMETHOD Flush(nsIMdbEnv* ev);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief);
|
||||
|
||||
|
||||
// { ----- begin versioning methods -----
|
||||
NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile** acqBud);
|
||||
// } ----- end versioning methods -----
|
||||
|
||||
// } ===== end nsIMdbFile methods =====
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected non-poly morkStdioFile methods
|
||||
|
||||
void new_stdio_file_fault(morkEnv* ev) const;
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkStdioFile methods
|
||||
|
||||
morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
|
||||
const char* inName, const char* inMode);
|
||||
// calls OpenStdio() after construction
|
||||
|
||||
morkStdioFile(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap,
|
||||
void* ioFile, const char* inName, mork_bool inFrozen);
|
||||
// calls UseStdio() after construction
|
||||
|
||||
void OpenStdio(morkEnv* ev, const char* inName, const char* inMode);
|
||||
// Open a new FILE with name inName, using mode flags from inMode.
|
||||
|
||||
void UseStdio(morkEnv* ev, void* ioFile, const char* inName,
|
||||
mork_bool inFrozen);
|
||||
// Use an existing file, like stdin/stdout/stderr, which should not
|
||||
// have the io stream closed when the file is closed. The ioFile
|
||||
// parameter must actually be of type FILE (but we don't want to make
|
||||
// this header file include the stdio.h header file).
|
||||
|
||||
void CloseStdio(morkEnv* ev);
|
||||
// Close the stream io if both and FileActive() and FileIoOpen(), but
|
||||
// this does not close this instances (like CloseStdioFile() does).
|
||||
// If stream io was made active by means of calling UseStdio(),
|
||||
// then this method does little beyond marking the stream inactive
|
||||
// because FileIoOpen() is false.
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakStdioFile(morkStdioFile* me,
|
||||
morkEnv* ev, morkStdioFile** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongStdioFile(morkStdioFile* me,
|
||||
morkEnv* ev, morkStdioFile** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKFILE_ */
|
|
@ -0,0 +1,460 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFACTORY_
|
||||
#include "morkFactory.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKHANDLE_
|
||||
#include "morkHandle.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkHandle::CloseMorkNode(morkEnv* ev) // CloseHandle() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseHandle(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkHandle::~morkHandle() // assert CloseHandle() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mHandle_Env==0);
|
||||
MORK_ASSERT(mHandle_Face==0);
|
||||
MORK_ASSERT(mHandle_Object==0);
|
||||
MORK_ASSERT(mHandle_Magic==0);
|
||||
MORK_ASSERT(mHandle_Tag==morkHandle_kTag); // should still have correct tag
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkHandle::morkHandle(morkEnv* ev, // note morkUsage is always morkUsage_kPool
|
||||
morkHandleFace* ioFace, // must not be nil, cookie for this handle
|
||||
morkObject* ioObject, // must not be nil, the object for this handle
|
||||
mork_magic inMagic) // magic sig to denote specific subclass
|
||||
: morkNode(ev, morkUsage::kPool, (nsIMdbHeap*) 0L)
|
||||
, mHandle_Tag( 0 )
|
||||
, mHandle_Env( ev )
|
||||
, mHandle_Face( ioFace )
|
||||
, mHandle_Object( 0 )
|
||||
, mHandle_Magic( 0 )
|
||||
{
|
||||
if ( ioFace && ioObject )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mHandle_Tag = morkHandle_kTag;
|
||||
morkObject::SlotStrongObject(ioObject, ev, &mHandle_Object);
|
||||
morkHandle::SlotWeakHandle(this, ev, &ioObject->mObject_Handle);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mHandle_Magic = inMagic;
|
||||
mNode_Derived = morkDerived_kHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->CantMakeWhenBadError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkHandle::CloseHandle(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
morkObject* obj = mHandle_Object;
|
||||
mork_bool objDidRefSelf = ( obj && obj->mObject_Handle == this );
|
||||
if ( objDidRefSelf )
|
||||
obj->mObject_Handle = 0; // drop the reference
|
||||
|
||||
morkObject::SlotStrongObject((morkObject*) 0, ev, &mHandle_Object);
|
||||
mHandle_Magic = 0;
|
||||
// note mHandle_Tag MUST stay morkHandle_kTag for morkNode::ZapOld()
|
||||
this->MarkShut();
|
||||
|
||||
if ( objDidRefSelf )
|
||||
this->CutWeakRef(ev); // do last, because it might self destroy
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
void morkHandle::NilFactoryError(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("nil mHandle_Factory");
|
||||
}
|
||||
|
||||
void morkHandle::NilHandleObjectError(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("nil mHandle_Object");
|
||||
}
|
||||
|
||||
void morkHandle::NonNodeObjectError(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("non-node mHandle_Object");
|
||||
}
|
||||
|
||||
void morkHandle::NonOpenObjectError(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("non-open mHandle_Object");
|
||||
}
|
||||
|
||||
void morkHandle::NewBadMagicHandleError(morkEnv* ev, mork_magic inMagic) const
|
||||
{
|
||||
MORK_USED_1(inMagic);
|
||||
ev->NewError("wrong mHandle_Magic");
|
||||
}
|
||||
|
||||
void morkHandle::NewDownHandleError(morkEnv* ev) const
|
||||
{
|
||||
if ( this->IsHandle() )
|
||||
{
|
||||
if ( this->GoodHandleTag() )
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
ev->NewError("unknown down morkHandle error");
|
||||
else
|
||||
this->NonOpenNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NewError("wrong morkHandle tag");
|
||||
}
|
||||
else
|
||||
ev->NewError("non morkHandle");
|
||||
}
|
||||
|
||||
morkObject* morkHandle::GetGoodHandleObject(morkEnv* ev,
|
||||
mork_bool inMutable, mork_magic inMagicType, mork_bool inClosedOkay) const
|
||||
{
|
||||
morkObject* outObject = 0;
|
||||
if ( this->IsHandle() && this->GoodHandleTag() &&
|
||||
( inClosedOkay || this->IsOpenNode() ) )
|
||||
{
|
||||
if ( !inMagicType || mHandle_Magic == inMagicType )
|
||||
{
|
||||
morkObject* obj = this->mHandle_Object;
|
||||
if ( obj )
|
||||
{
|
||||
if ( obj->IsNode() )
|
||||
{
|
||||
if ( inClosedOkay || obj->IsOpenNode() )
|
||||
{
|
||||
if ( this->IsMutable() || !inMutable )
|
||||
outObject = obj;
|
||||
else
|
||||
this->NonMutableNodeError(ev);
|
||||
}
|
||||
else
|
||||
this->NonOpenObjectError(ev);
|
||||
}
|
||||
else
|
||||
this->NonNodeObjectError(ev);
|
||||
}
|
||||
else if ( !inClosedOkay )
|
||||
this->NilHandleObjectError(ev);
|
||||
}
|
||||
else
|
||||
this->NewBadMagicHandleError(ev, inMagicType);
|
||||
}
|
||||
else
|
||||
this->NewDownHandleError(ev);
|
||||
|
||||
MORK_ASSERT(outObject || inClosedOkay);
|
||||
return outObject;
|
||||
}
|
||||
|
||||
|
||||
morkEnv*
|
||||
morkHandle::CanUseHandle(nsIMdbEnv* mev, mork_bool inMutable,
|
||||
mork_bool inClosedOkay, mdb_err* outErr) const
|
||||
{
|
||||
morkEnv* outEnv = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkObject* obj = this->GetGoodHandleObject(ev, inMutable,
|
||||
/*magic*/ 0, inClosedOkay);
|
||||
if ( obj )
|
||||
{
|
||||
outEnv = ev;
|
||||
}
|
||||
*outErr = ev->AsErr();
|
||||
}
|
||||
MORK_ASSERT(outEnv || inClosedOkay);
|
||||
return outEnv;
|
||||
}
|
||||
|
||||
// { ===== begin nsIMdbObject methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool readOnly = mdbBool_kTrue;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
readOnly = mHandle_Object->IsFrozen();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
MORK_ASSERT(outIsReadonly);
|
||||
if ( outIsReadonly )
|
||||
*outIsReadonly = readOnly;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin factory methods -----
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbFactory* handle = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkFactory* factory = ev->mEnv_Factory;
|
||||
if ( factory )
|
||||
{
|
||||
handle = factory;
|
||||
NS_ADDREF(handle);
|
||||
}
|
||||
else
|
||||
this->NilFactoryError(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
MORK_ASSERT(acqFactory);
|
||||
if ( acqFactory )
|
||||
*acqFactory = handle;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end factory methods -----
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_GetWeakRefCount(nsIMdbEnv* mev, // weak refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_count count = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
count = this->WeakRefsOnly();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
MORK_ASSERT(outCount);
|
||||
if ( outCount )
|
||||
*outCount = count;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_GetStrongRefCount(nsIMdbEnv* mev, // strong refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_count count = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
count = this->StrongRefsOnly();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
MORK_ASSERT(outCount);
|
||||
if ( outCount )
|
||||
*outCount = count;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_AddWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
this->AddWeakRef(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
}
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_AddStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
this->AddStrongRef(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_CutWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
this->CutWeakRef(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
|
||||
return outErr;
|
||||
}
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_CutStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
this->CutStrongRef(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_CloseMdbObject(nsIMdbEnv* mev)
|
||||
// called at strong refs zero
|
||||
{
|
||||
// if only one ref, Handle_CutStrongRef will clean up better.
|
||||
if (mNode_Uses == 1)
|
||||
return Handle_CutStrongRef(mev);
|
||||
|
||||
mdb_err outErr = 0;
|
||||
|
||||
if ( this->IsNode() && this->IsOpenNode() )
|
||||
{
|
||||
morkEnv* ev = CanUseHandle(mev, /*inMutable*/ morkBool_kFalse,
|
||||
/*inClosedOkay*/ morkBool_kTrue, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkObject* object = mHandle_Object;
|
||||
if ( object && object->IsNode() && object->IsOpenNode() )
|
||||
object->CloseMorkNode(ev);
|
||||
|
||||
this->CloseMorkNode(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkHandle::Handle_IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
|
||||
{
|
||||
MORK_USED_1(mev);
|
||||
mdb_err outErr = 0;
|
||||
|
||||
MORK_ASSERT(outOpen);
|
||||
if ( outOpen )
|
||||
*outOpen = this->IsOpenNode();
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end ref counting -----
|
||||
|
||||
// } ===== end nsIMdbObject methods =====
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKHANDLE_
|
||||
#define _MORKHANDLE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class morkPool;
|
||||
class morkObject;
|
||||
class morkFactory;
|
||||
|
||||
#define morkDerived_kHandle /*i*/ 0x486E /* ascii 'Hn' */
|
||||
#define morkHandle_kTag 0x68416E44 /* ascii 'hAnD' */
|
||||
|
||||
/*| morkHandle:
|
||||
|*/
|
||||
class morkHandle : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
mork_u4 mHandle_Tag; // must equal morkHandle_kTag
|
||||
morkEnv* mHandle_Env; // pool that allocated this handle
|
||||
morkHandleFace* mHandle_Face; // cookie from pool containing this
|
||||
morkObject* mHandle_Object; // object this handle wraps for MDB API
|
||||
mork_magic mHandle_Magic; // magic sig different in each subclass
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseHandle() only if open
|
||||
virtual ~morkHandle(); // assert that CloseHandle() executed earlier
|
||||
|
||||
public: // morkHandle construction & destruction
|
||||
morkHandle(morkEnv* ev, // note morkUsage is always morkUsage_kPool
|
||||
morkHandleFace* ioFace, // must not be nil, cookie for this handle
|
||||
morkObject* ioObject, // must not be nil, the object for this handle
|
||||
mork_magic inMagic); // magic sig to denote specific subclass
|
||||
void CloseHandle(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkHandle(const morkHandle& other);
|
||||
morkHandle& operator=(const morkHandle& other);
|
||||
|
||||
protected: // special case empty construction for morkHandleFrame
|
||||
friend class morkHandleFrame;
|
||||
morkHandle() { }
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsHandle() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kHandle; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // morkHandle memory management operators
|
||||
void* operator new(size_t inSize, morkPool& ioPool, morkZone& ioZone, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return ioPool.NewHandle(ev, inSize, &ioZone); }
|
||||
|
||||
void* operator new(size_t inSize, morkPool& ioPool, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return ioPool.NewHandle(ev, inSize, (morkZone*) 0); }
|
||||
|
||||
void* operator new(size_t inSize, morkHandleFace* ioFace) CPP_THROW_NEW
|
||||
{ MORK_USED_1(inSize); return ioFace; }
|
||||
|
||||
|
||||
public: // other handle methods
|
||||
mork_bool GoodHandleTag() const
|
||||
{ return mHandle_Tag == morkHandle_kTag; }
|
||||
|
||||
void NewBadMagicHandleError(morkEnv* ev, mork_magic inMagic) const;
|
||||
void NewDownHandleError(morkEnv* ev) const;
|
||||
void NilFactoryError(morkEnv* ev) const;
|
||||
void NilHandleObjectError(morkEnv* ev) const;
|
||||
void NonNodeObjectError(morkEnv* ev) const;
|
||||
void NonOpenObjectError(morkEnv* ev) const;
|
||||
|
||||
morkObject* GetGoodHandleObject(morkEnv* ev,
|
||||
mork_bool inMutable, mork_magic inMagicType, mork_bool inClosedOkay) const;
|
||||
|
||||
public: // interface supporting mdbObject methods
|
||||
|
||||
morkEnv* CanUseHandle(nsIMdbEnv* mev, mork_bool inMutable,
|
||||
mork_bool inClosedOkay, mdb_err* outErr) const;
|
||||
|
||||
// { ----- begin mdbObject style methods -----
|
||||
mdb_err Handle_IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly);
|
||||
|
||||
mdb_err Handle_GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory);
|
||||
mdb_err Handle_GetWeakRefCount(nsIMdbEnv* ev, mdb_count* outCount);
|
||||
mdb_err Handle_GetStrongRefCount(nsIMdbEnv* ev, mdb_count* outCount);
|
||||
|
||||
mdb_err Handle_AddWeakRef(nsIMdbEnv* ev);
|
||||
mdb_err Handle_AddStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
mdb_err Handle_CutWeakRef(nsIMdbEnv* ev);
|
||||
mdb_err Handle_CutStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
mdb_err Handle_CloseMdbObject(nsIMdbEnv* ev);
|
||||
mdb_err Handle_IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen);
|
||||
// } ----- end mdbObject style methods -----
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakHandle(morkHandle* me,
|
||||
morkEnv* ev, morkHandle** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongHandle(morkHandle* me,
|
||||
morkEnv* ev, morkHandle** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
#define morkHandleFrame_kPadSlotCount 4
|
||||
|
||||
/*| morkHandleFrame: an object format used for allocating and maintaining
|
||||
**| instances of morkHandle, with leading slots used to maintain this in a
|
||||
**| linked list, and following slots to provide extra footprint that might
|
||||
**| be needed by any morkHandle subclasses that include very little extra
|
||||
**| space (by virtue of the fact that each morkHandle subclass is expected
|
||||
**| to multiply inherit from another base class that has only abstact methods
|
||||
**| for space overhead related only to some vtable representation).
|
||||
|*/
|
||||
class morkHandleFrame {
|
||||
public:
|
||||
morkLink mHandleFrame_Link; // list storage without trampling Handle
|
||||
morkHandle mHandleFrame_Handle;
|
||||
mork_ip mHandleFrame_Padding[ morkHandleFrame_kPadSlotCount ];
|
||||
|
||||
public:
|
||||
morkHandle* AsHandle() { return &mHandleFrame_Handle; }
|
||||
|
||||
morkHandleFrame() {} // actually, morkHandleFrame never gets constructed
|
||||
|
||||
private: // copying is not allowed
|
||||
morkHandleFrame(const morkHandleFrame& other);
|
||||
morkHandleFrame& operator=(const morkHandleFrame& other);
|
||||
};
|
||||
|
||||
#define morkHandleFrame_kHandleOffset \
|
||||
mork_OffsetOf(morkHandleFrame,mHandleFrame_Handle)
|
||||
|
||||
#define morkHandle_AsHandleFrame(h) ((h)->mHandle_Block , \
|
||||
((morkHandleFrame*) (((mork_u1*)(h)) - morkHandleFrame_kHandleOffset)))
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKHANDLE_ */
|
|
@ -0,0 +1,280 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#include "morkIntMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkIntMap::CloseMorkNode(morkEnv* ev) // CloseIntMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseIntMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkIntMap::~morkIntMap() // assert CloseIntMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkIntMap::morkIntMap(morkEnv* ev,
|
||||
const morkUsage& inUsage, mork_size inValSize,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_bool inHoldChanges)
|
||||
: morkMap(ev, inUsage, ioHeap, sizeof(mork_u4), inValSize,
|
||||
morkIntMap_kStartSlotCount, ioSlotHeap, inHoldChanges)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kIntMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkIntMap::CloseIntMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
|
||||
morkIntMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return *((const mork_u4*) inKeyA) == *((const mork_u4*) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
morkIntMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return *((const mork_u4*) inKey);
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
mork_bool
|
||||
morkIntMap::AddInt(morkEnv* ev, mork_u4 inKey, void* ioAddress)
|
||||
// the AddInt() method return value equals ev->Good().
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->Put(ev, &inKey, &ioAddress,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
}
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkIntMap::CutInt(morkEnv* ev, mork_u4 inKey)
|
||||
{
|
||||
return this->Cut(ev, &inKey, /*key*/ (void*) 0, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
}
|
||||
|
||||
void*
|
||||
morkIntMap::GetInt(morkEnv* ev, mork_u4 inKey)
|
||||
// Note the returned val does NOT have an increase in refcount for this.
|
||||
{
|
||||
void* val = 0; // old val in the map
|
||||
this->Get(ev, &inKey, /*key*/ (void*) 0, &val, (mork_change**) 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkIntMap::HasInt(morkEnv* ev, mork_u4 inKey)
|
||||
// Note the returned val does NOT have an increase in refcount for this.
|
||||
{
|
||||
return this->Get(ev, &inKey, /*key*/ (void*) 0, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#ifdef MORK_POINTER_MAP_IMPL
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkPointerMap::CloseMorkNode(morkEnv* ev) // ClosePointerMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->ClosePointerMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkPointerMap::~morkPointerMap() // assert ClosePointerMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkPointerMap::morkPointerMap(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkMap(ev, inUsage, ioHeap, sizeof(void*), sizeof(void*),
|
||||
morkPointerMap_kStartSlotCount, ioSlotHeap,
|
||||
/*inHoldChanges*/ morkBool_kFalse)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kPointerMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkPointerMap::ClosePointerMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool // *((void**) inKeyA) == *((void**) inKeyB)
|
||||
morkPointerMap::Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return *((const void**) inKeyA) == *((const void**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
morkPointerMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return *((const mork_u4*) inKey);
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
mork_bool
|
||||
morkPointerMap::AddPointer(morkEnv* ev, void* inKey, void* ioAddress)
|
||||
// the AddPointer() method return value equals ev->Good().
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->Put(ev, &inKey, &ioAddress,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
}
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkPointerMap::CutPointer(morkEnv* ev, void* inKey)
|
||||
{
|
||||
return this->Cut(ev, &inKey, /*key*/ (void*) 0, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
}
|
||||
|
||||
void*
|
||||
morkPointerMap::GetPointer(morkEnv* ev, void* inKey)
|
||||
// Note the returned val does NOT have an increase in refcount for this.
|
||||
{
|
||||
void* val = 0; // old val in the map
|
||||
this->Get(ev, &inKey, /*key*/ (void*) 0, &val, (mork_change**) 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkPointerMap::HasPointer(morkEnv* ev, void* inKey)
|
||||
// Note the returned val does NOT have an increase in refcount for this.
|
||||
{
|
||||
return this->Get(ev, &inKey, /*key*/ (void*) 0, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
}
|
||||
#endif /*MORK_POINTER_MAP_IMPL*/
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#define _MORKINTMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kIntMap /*i*/ 0x694D /* ascii 'iM' */
|
||||
|
||||
#define morkIntMap_kStartSlotCount 256
|
||||
|
||||
/*| morkIntMap: maps mork_token -> morkNode
|
||||
|*/
|
||||
class morkIntMap : public morkMap { // for mapping tokens to maps
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseIntMap() only if open
|
||||
virtual ~morkIntMap(); // assert that CloseIntMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
|
||||
// keySize for morkIntMap equals sizeof(mork_u4)
|
||||
morkIntMap(morkEnv* ev, const morkUsage& inUsage, mork_size inValSize,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_bool inHoldChanges);
|
||||
void CloseIntMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsIntMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kIntMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // *((mork_u4*) inKeyA) == *((mork_u4*) inKeyB)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
|
||||
virtual mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddInt(morkEnv* ev, mork_u4 inKey, void* ioAddress);
|
||||
// the AddInt() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutInt(morkEnv* ev, mork_u4 inKey);
|
||||
// The CutInt() boolean return indicates whether removal happened.
|
||||
|
||||
void* GetInt(morkEnv* ev, mork_u4 inKey);
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
|
||||
mork_bool HasInt(morkEnv* ev, mork_u4 inKey);
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#ifdef MORK_POINTER_MAP_IMPL
|
||||
|
||||
#define morkDerived_kPointerMap /*i*/ 0x704D /* ascii 'pM' */
|
||||
|
||||
#define morkPointerMap_kStartSlotCount 256
|
||||
|
||||
/*| morkPointerMap: maps void* -> void*
|
||||
**|
|
||||
**| This pointer map class is equivalent to morkIntMap when sizeof(mork_u4)
|
||||
**| equals sizeof(void*). However, when these two sizes are different,
|
||||
**| then we cannot use the same hash table structure very easily without
|
||||
**| being very careful about the size and usage assumptions of those
|
||||
**| clients using the smaller data type. So we just go ahead and use
|
||||
**| morkPointerMap for hash tables using pointer key types.
|
||||
|*/
|
||||
class morkPointerMap : public morkMap { // for mapping tokens to maps
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // ClosePointerMap() only if open
|
||||
virtual ~morkPointerMap(); // assert that ClosePointerMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
|
||||
// keySize for morkPointerMap equals sizeof(mork_u4)
|
||||
morkPointerMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void ClosePointerMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsPointerMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kPointerMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // *((void**) inKeyA) == *((void**) inKeyB)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
|
||||
virtual mork_u4 // some integer function of *((mork_u4*) inKey)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddPointer(morkEnv* ev, void* inKey, void* ioAddress);
|
||||
// the AddPointer() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutPointer(morkEnv* ev, void* inKey);
|
||||
// The CutPointer() boolean return indicates whether removal happened.
|
||||
|
||||
void* GetPointer(morkEnv* ev, void* inKey);
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
|
||||
mork_bool HasPointer(morkEnv* ev, void* inKey);
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakIntMap(morkIntMap* me,
|
||||
morkEnv* ev, morkIntMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongIntMap(morkIntMap* me,
|
||||
morkEnv* ev, morkIntMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
};
|
||||
#endif /*MORK_POINTER_MAP_IMPL*/
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKINTMAP_ */
|
|
@ -0,0 +1,960 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// This code is mostly a port to C++ from public domain IronDoc C sources.
|
||||
// Note many code comments here come verbatim from cut-and-pasted IronDoc.
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
|
||||
class morkHashArrays {
|
||||
public:
|
||||
nsIMdbHeap* mHashArrays_Heap; // copy of mMap_Heap
|
||||
mork_count mHashArrays_Slots; // copy of mMap_Slots
|
||||
|
||||
mork_u1* mHashArrays_Keys; // copy of mMap_Keys
|
||||
mork_u1* mHashArrays_Vals; // copy of mMap_Vals
|
||||
morkAssoc* mHashArrays_Assocs; // copy of mMap_Assocs
|
||||
mork_change* mHashArrays_Changes; // copy of mMap_Changes
|
||||
morkAssoc** mHashArrays_Buckets; // copy of mMap_Buckets
|
||||
morkAssoc* mHashArrays_FreeList; // copy of mMap_FreeList
|
||||
|
||||
public:
|
||||
void finalize(morkEnv* ev);
|
||||
};
|
||||
|
||||
void morkHashArrays::finalize(morkEnv* ev)
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbHeap* heap = mHashArrays_Heap;
|
||||
|
||||
if ( heap )
|
||||
{
|
||||
if ( mHashArrays_Keys )
|
||||
heap->Free(menv, mHashArrays_Keys);
|
||||
if ( mHashArrays_Vals )
|
||||
heap->Free(menv, mHashArrays_Vals);
|
||||
if ( mHashArrays_Assocs )
|
||||
heap->Free(menv, mHashArrays_Assocs);
|
||||
if ( mHashArrays_Changes )
|
||||
heap->Free(menv, mHashArrays_Changes);
|
||||
if ( mHashArrays_Buckets )
|
||||
heap->Free(menv, mHashArrays_Buckets);
|
||||
}
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkMap::CloseMorkNode(morkEnv* ev) // CloseMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkMap::~morkMap() // assert CloseMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mMap_FreeList==0);
|
||||
MORK_ASSERT(mMap_Buckets==0);
|
||||
MORK_ASSERT(mMap_Keys==0);
|
||||
MORK_ASSERT(mMap_Vals==0);
|
||||
MORK_ASSERT(mMap_Changes==0);
|
||||
MORK_ASSERT(mMap_Assocs==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkMap::CloseMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
nsIMdbHeap* heap = mMap_Heap;
|
||||
if ( heap ) /* need to free the arrays? */
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
|
||||
if ( mMap_Keys )
|
||||
heap->Free(menv, mMap_Keys);
|
||||
|
||||
if ( mMap_Vals )
|
||||
heap->Free(menv, mMap_Vals);
|
||||
|
||||
if ( mMap_Assocs )
|
||||
heap->Free(menv, mMap_Assocs);
|
||||
|
||||
if ( mMap_Buckets )
|
||||
heap->Free(menv, mMap_Buckets);
|
||||
|
||||
if ( mMap_Changes )
|
||||
heap->Free(menv, mMap_Changes);
|
||||
}
|
||||
mMap_Keys = 0;
|
||||
mMap_Vals = 0;
|
||||
mMap_Buckets = 0;
|
||||
mMap_Assocs = 0;
|
||||
mMap_Changes = 0;
|
||||
mMap_FreeList = 0;
|
||||
MORK_MEMSET(&mMap_Form, 0, sizeof(morkMapForm));
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
void
|
||||
morkMap::clear_map(morkEnv* ev, nsIMdbHeap* ioSlotHeap)
|
||||
{
|
||||
mMap_Tag = 0;
|
||||
mMap_Seed = 0;
|
||||
mMap_Slots = 0;
|
||||
mMap_Fill = 0;
|
||||
mMap_Keys = 0;
|
||||
mMap_Vals = 0;
|
||||
mMap_Assocs = 0;
|
||||
mMap_Changes = 0;
|
||||
mMap_Buckets = 0;
|
||||
mMap_FreeList = 0;
|
||||
MORK_MEMSET(&mMap_Form, 0, sizeof(morkMapForm));
|
||||
|
||||
mMap_Heap = 0;
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mMap_Heap);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkMap::morkMap(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_size inKeySize, mork_size inValSize,
|
||||
mork_size inSlots, nsIMdbHeap* ioSlotHeap, mork_bool inHoldChanges)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
, mMap_Heap( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->clear_map(ev, ioSlotHeap);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mMap_Form.mMapForm_HoldChanges = inHoldChanges;
|
||||
|
||||
mMap_Form.mMapForm_KeySize = inKeySize;
|
||||
mMap_Form.mMapForm_ValSize = inValSize;
|
||||
mMap_Form.mMapForm_KeyIsIP = ( inKeySize == sizeof(mork_ip) );
|
||||
mMap_Form.mMapForm_ValIsIP = ( inValSize == sizeof(mork_ip) );
|
||||
|
||||
this->InitMap(ev, inSlots);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkMap::NewIterOutOfSyncError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("map iter out of sync");
|
||||
}
|
||||
|
||||
void morkMap::NewBadMapError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad morkMap tag");
|
||||
if ( !this )
|
||||
ev->NewError("nil morkMap instance");
|
||||
}
|
||||
|
||||
void morkMap::NewSlotsUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("member count underflow");
|
||||
}
|
||||
|
||||
void morkMap::InitMap(morkEnv* ev, mork_size inSlots)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
morkHashArrays old;
|
||||
// MORK_MEMCPY(&mMap_Form, &inForm, sizeof(morkMapForm));
|
||||
if ( inSlots < 3 ) /* requested capacity absurdly small? */
|
||||
inSlots = 3; /* bump it up to a minimum practical level */
|
||||
else if ( inSlots > (128 * 1024) ) /* requested slots absurdly big? */
|
||||
inSlots = (128 * 1024); /* decrease it to a maximum practical level */
|
||||
|
||||
if ( this->new_arrays(ev, &old, inSlots) )
|
||||
mMap_Tag = morkMap_kTag;
|
||||
|
||||
MORK_MEMSET(&old, 0, sizeof(morkHashArrays)); // do NOT finalize
|
||||
}
|
||||
}
|
||||
|
||||
morkAssoc**
|
||||
morkMap::find(morkEnv* ev, const void* inKey, mork_u4 inHash) const
|
||||
{
|
||||
mork_u1* keys = mMap_Keys;
|
||||
mork_num keySize = this->FormKeySize();
|
||||
// morkMap_mEqual equal = this->FormEqual();
|
||||
|
||||
morkAssoc** ref = mMap_Buckets + (inHash % mMap_Slots);
|
||||
morkAssoc* assoc = *ref;
|
||||
while ( assoc ) /* look at another assoc in the bucket? */
|
||||
{
|
||||
mork_pos i = assoc - mMap_Assocs; /* index of this assoc */
|
||||
if ( this->Equal(ev, keys + (i * keySize), inKey) ) /* found? */
|
||||
return ref;
|
||||
|
||||
ref = &assoc->mAssoc_Next; /* consider next assoc slot in bucket */
|
||||
assoc = *ref; /* if this is null, then we are done */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*| get_assoc: read the key and/or value at index inPos
|
||||
|*/
|
||||
void
|
||||
morkMap::get_assoc(void* outKey, void* outVal, mork_pos inPos) const
|
||||
{
|
||||
mork_num valSize = this->FormValSize();
|
||||
if ( valSize && outVal ) /* map holds values? caller wants the value? */
|
||||
{
|
||||
const mork_u1* value = mMap_Vals + (valSize * inPos);
|
||||
if ( valSize == sizeof(mork_ip) && this->FormValIsIP() ) /* ip case? */
|
||||
*((mork_ip*) outVal) = *((const mork_ip*) value);
|
||||
else
|
||||
MORK_MEMCPY(outVal, value, valSize);
|
||||
}
|
||||
if ( outKey ) /* caller wants the key? */
|
||||
{
|
||||
mork_num keySize = this->FormKeySize();
|
||||
const mork_u1* key = mMap_Keys + (keySize * inPos);
|
||||
if ( keySize == sizeof(mork_ip) && this->FormKeyIsIP() ) /* ip case? */
|
||||
*((mork_ip*) outKey) = *((const mork_ip*) key);
|
||||
else
|
||||
MORK_MEMCPY(outKey, key, keySize);
|
||||
}
|
||||
}
|
||||
|
||||
/*| put_assoc: write the key and/or value at index inPos
|
||||
|*/
|
||||
void
|
||||
morkMap::put_assoc(const void* inKey, const void* inVal, mork_pos inPos) const
|
||||
{
|
||||
mork_num valSize = this->FormValSize();
|
||||
if ( valSize && inVal ) /* map holds values? caller sends a value? */
|
||||
{
|
||||
mork_u1* value = mMap_Vals + (valSize * inPos);
|
||||
if ( valSize == sizeof(mork_ip) && this->FormValIsIP() ) /* ip case? */
|
||||
*((mork_ip*) value) = *((const mork_ip*) inVal);
|
||||
else
|
||||
MORK_MEMCPY(value, inVal, valSize);
|
||||
}
|
||||
if ( inKey ) /* caller sends a key? */
|
||||
{
|
||||
mork_num keySize = this->FormKeySize();
|
||||
mork_u1* key = mMap_Keys + (keySize * inPos);
|
||||
if ( keySize == sizeof(mork_ip) && this->FormKeyIsIP() ) /* ip case? */
|
||||
*((mork_ip*) key) = *((const mork_ip*) inKey);
|
||||
else
|
||||
MORK_MEMCPY(key, inKey, keySize);
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
morkMap::clear_alloc(morkEnv* ev, mork_size inSize)
|
||||
{
|
||||
void* p = 0;
|
||||
nsIMdbHeap* heap = mMap_Heap;
|
||||
if ( heap )
|
||||
{
|
||||
if ( heap->Alloc(ev->AsMdbEnv(), inSize, (void**) &p) == 0 && p )
|
||||
{
|
||||
MORK_MEMSET(p, 0, inSize);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return (void*) 0;
|
||||
}
|
||||
|
||||
void*
|
||||
morkMap::alloc(morkEnv* ev, mork_size inSize)
|
||||
{
|
||||
void* p = 0;
|
||||
nsIMdbHeap* heap = mMap_Heap;
|
||||
if ( heap )
|
||||
{
|
||||
if ( heap->Alloc(ev->AsMdbEnv(), inSize, (void**) &p) == 0 && p )
|
||||
return p;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return (void*) 0;
|
||||
}
|
||||
|
||||
/*| new_keys: allocate an array of inSlots new keys filled with zero.
|
||||
|*/
|
||||
mork_u1*
|
||||
morkMap::new_keys(morkEnv* ev, mork_num inSlots)
|
||||
{
|
||||
mork_num size = inSlots * this->FormKeySize();
|
||||
return (mork_u1*) this->clear_alloc(ev, size);
|
||||
}
|
||||
|
||||
/*| new_values: allocate an array of inSlots new values filled with zero.
|
||||
**| When values are zero sized, we just return a null pointer.
|
||||
|*/
|
||||
mork_u1*
|
||||
morkMap::new_values(morkEnv* ev, mork_num inSlots)
|
||||
{
|
||||
mork_u1* values = 0;
|
||||
mork_num size = inSlots * this->FormValSize();
|
||||
if ( size )
|
||||
values = (mork_u1*) this->clear_alloc(ev, size);
|
||||
return values;
|
||||
}
|
||||
|
||||
mork_change*
|
||||
morkMap::new_changes(morkEnv* ev, mork_num inSlots)
|
||||
{
|
||||
mork_change* changes = 0;
|
||||
mork_num size = inSlots * sizeof(mork_change);
|
||||
if ( size && mMap_Form.mMapForm_HoldChanges )
|
||||
changes = (mork_change*) this->clear_alloc(ev, size);
|
||||
return changes;
|
||||
}
|
||||
|
||||
/*| new_buckets: allocate an array of inSlots new buckets filled with zero.
|
||||
|*/
|
||||
morkAssoc**
|
||||
morkMap::new_buckets(morkEnv* ev, mork_num inSlots)
|
||||
{
|
||||
mork_num size = inSlots * sizeof(morkAssoc*);
|
||||
return (morkAssoc**) this->clear_alloc(ev, size);
|
||||
}
|
||||
|
||||
/*| new_assocs: allocate an array of inSlots new assocs, with each assoc
|
||||
**| linked together in a list with the first array element at the list head
|
||||
**| and the last element at the list tail. (morkMap::grow() needs this.)
|
||||
|*/
|
||||
morkAssoc*
|
||||
morkMap::new_assocs(morkEnv* ev, mork_num inSlots)
|
||||
{
|
||||
mork_num size = inSlots * sizeof(morkAssoc);
|
||||
morkAssoc* assocs = (morkAssoc*) this->alloc(ev, size);
|
||||
if ( assocs ) /* able to allocate the array? */
|
||||
{
|
||||
morkAssoc* a = assocs + (inSlots - 1); /* the last array element */
|
||||
a->mAssoc_Next = 0; /* terminate tail element of the list with null */
|
||||
while ( --a >= assocs ) /* another assoc to link into the list? */
|
||||
a->mAssoc_Next = a + 1; /* each points to the following assoc */
|
||||
}
|
||||
return assocs;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkMap::new_arrays(morkEnv* ev, morkHashArrays* old, mork_num inSlots)
|
||||
{
|
||||
mork_bool outNew = morkBool_kFalse;
|
||||
|
||||
/* see if we can allocate all the new arrays before we go any further: */
|
||||
morkAssoc** newBuckets = this->new_buckets(ev, inSlots);
|
||||
morkAssoc* newAssocs = this->new_assocs(ev, inSlots);
|
||||
mork_u1* newKeys = this->new_keys(ev, inSlots);
|
||||
mork_u1* newValues = this->new_values(ev, inSlots);
|
||||
mork_change* newChanges = this->new_changes(ev, inSlots);
|
||||
|
||||
/* it is okay for newChanges to be null when changes are not held: */
|
||||
mork_bool okayChanges = ( newChanges || !this->FormHoldChanges() );
|
||||
|
||||
/* it is okay for newValues to be null when values are zero sized: */
|
||||
mork_bool okayValues = ( newValues || !this->FormValSize() );
|
||||
|
||||
if ( newBuckets && newAssocs && newKeys && okayChanges && okayValues )
|
||||
{
|
||||
outNew = morkBool_kTrue; /* yes, we created all the arrays we need */
|
||||
|
||||
/* init the old hashArrays with slots from this hash table: */
|
||||
old->mHashArrays_Heap = mMap_Heap;
|
||||
|
||||
old->mHashArrays_Slots = mMap_Slots;
|
||||
old->mHashArrays_Keys = mMap_Keys;
|
||||
old->mHashArrays_Vals = mMap_Vals;
|
||||
old->mHashArrays_Assocs = mMap_Assocs;
|
||||
old->mHashArrays_Buckets = mMap_Buckets;
|
||||
old->mHashArrays_Changes = mMap_Changes;
|
||||
|
||||
/* now replace all our array slots with the new structures: */
|
||||
++mMap_Seed; /* note the map is now changed */
|
||||
mMap_Keys = newKeys;
|
||||
mMap_Vals = newValues;
|
||||
mMap_Buckets = newBuckets;
|
||||
mMap_Assocs = newAssocs;
|
||||
mMap_FreeList = newAssocs; /* all are free to start with */
|
||||
mMap_Changes = newChanges;
|
||||
mMap_Slots = inSlots;
|
||||
}
|
||||
else /* free the partial set of arrays that were actually allocated */
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbHeap* heap = mMap_Heap;
|
||||
if ( newBuckets )
|
||||
heap->Free(menv, newBuckets);
|
||||
if ( newAssocs )
|
||||
heap->Free(menv, newAssocs);
|
||||
if ( newKeys )
|
||||
heap->Free(menv, newKeys);
|
||||
if ( newValues )
|
||||
heap->Free(menv, newValues);
|
||||
if ( newChanges )
|
||||
heap->Free(menv, newChanges);
|
||||
|
||||
MORK_MEMSET(old, 0, sizeof(morkHashArrays));
|
||||
}
|
||||
|
||||
return outNew;
|
||||
}
|
||||
|
||||
/*| grow: make the map arrays bigger by 33%. The old map is completely
|
||||
**| full, or else we would not have called grow() to get more space. This
|
||||
**| means the free list is empty, and also means every old key and value is in
|
||||
**| use in the old arrays. So every key and value must be copied to the new
|
||||
**| arrays, and since they are contiguous in the old arrays, we can efficiently
|
||||
**| bitwise copy them in bulk from the old arrays to the new arrays, without
|
||||
**| paying any attention to the structure of the old arrays.
|
||||
**|
|
||||
**|| The content of the old bucket and assoc arrays need not be copied because
|
||||
**| this information is going to be completely rebuilt by rehashing all the
|
||||
**| keys into their new buckets, given the new larger map capacity. The new
|
||||
**| bucket array from new_arrays() is assumed to contain all zeroes, which is
|
||||
**| necessary to ensure the lists in each bucket stay null terminated as we
|
||||
**| build the new linked lists. (Note no old bucket ordering is preserved.)
|
||||
**|
|
||||
**|| If the old capacity is N, then in the new arrays the assocs with indexes
|
||||
**| from zero to N-1 are still allocated and must be rehashed into the map.
|
||||
**| The new free list contains all the following assocs, starting with the new
|
||||
**| assoc link at index N. (We call the links in the link array "assocs"
|
||||
**| because allocating a link is the same as allocating the key/value pair
|
||||
**| with the same index as the link.)
|
||||
**|
|
||||
**|| The new free list is initialized simply by pointing at the first new link
|
||||
**| in the assoc array after the size of the old assoc array. This assumes
|
||||
**| that FeHashTable_new_arrays() has already linked all the new assocs into a
|
||||
**| list with the first at the head of the list and the last at the tail of the
|
||||
**| list. So by making the free list point to the first of the new uncopied
|
||||
**| assocs, the list is already well-formed.
|
||||
|*/
|
||||
mork_bool morkMap::grow(morkEnv* ev)
|
||||
{
|
||||
if ( mMap_Heap ) /* can we grow the map? */
|
||||
{
|
||||
mork_num newSlots = (mMap_Slots * 2); /* +100% */
|
||||
morkHashArrays old; /* a place to temporarily hold all the old arrays */
|
||||
if ( this->new_arrays(ev, &old, newSlots) ) /* have more? */
|
||||
{
|
||||
// morkMap_mHash hash = this->FormHash(); /* for terse loop use */
|
||||
|
||||
/* figure out the bulk volume sizes of old keys and values to move: */
|
||||
mork_num oldSlots = old.mHashArrays_Slots; /* number of old assocs */
|
||||
mork_num keyBulk = oldSlots * this->FormKeySize(); /* key volume */
|
||||
mork_num valBulk = oldSlots * this->FormValSize(); /* values */
|
||||
|
||||
/* convenient variables for new arrays that need to be rehashed: */
|
||||
morkAssoc** newBuckets = mMap_Buckets; /* new all zeroes */
|
||||
morkAssoc* newAssocs = mMap_Assocs; /* hash into buckets */
|
||||
morkAssoc* newFreeList = newAssocs + oldSlots; /* new room is free */
|
||||
mork_u1* key = mMap_Keys; /* the first key to rehash */
|
||||
--newAssocs; /* back up one before preincrement used in while loop */
|
||||
|
||||
/* move all old keys and values to the new arrays: */
|
||||
MORK_MEMCPY(mMap_Keys, old.mHashArrays_Keys, keyBulk);
|
||||
if ( valBulk ) /* are values nonzero sized? */
|
||||
MORK_MEMCPY(mMap_Vals, old.mHashArrays_Vals, valBulk);
|
||||
|
||||
mMap_FreeList = newFreeList; /* remaining assocs are free */
|
||||
|
||||
while ( ++newAssocs < newFreeList ) /* rehash another old assoc? */
|
||||
{
|
||||
morkAssoc** top = newBuckets + (this->Hash(ev, key) % newSlots);
|
||||
key += this->FormKeySize(); /* the next key to rehash */
|
||||
newAssocs->mAssoc_Next = *top; /* link to prev bucket top */
|
||||
*top = newAssocs; /* push assoc on top of bucket */
|
||||
}
|
||||
++mMap_Seed; /* note the map has changed */
|
||||
old.finalize(ev); /* remember to free the old arrays */
|
||||
}
|
||||
}
|
||||
else ev->OutOfMemoryError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
|
||||
mork_bool
|
||||
morkMap::Put(morkEnv* ev, const void* inKey, const void* inVal,
|
||||
void* outKey, void* outVal, mork_change** outChange)
|
||||
{
|
||||
mork_bool outPut = morkBool_kFalse;
|
||||
|
||||
if ( this->GoodMap() ) /* looks good? */
|
||||
{
|
||||
mork_u4 hash = this->Hash(ev, inKey);
|
||||
morkAssoc** ref = this->find(ev, inKey, hash);
|
||||
if ( ref ) /* assoc was found? reuse an existing assoc slot? */
|
||||
{
|
||||
outPut = morkBool_kTrue; /* inKey was indeed already inside the map */
|
||||
}
|
||||
else /* assoc not found -- need to allocate a new assoc slot */
|
||||
{
|
||||
morkAssoc* assoc = this->pop_free_assoc();
|
||||
if ( !assoc ) /* no slots remaining in free list? must grow map? */
|
||||
{
|
||||
if ( this->grow(ev) ) /* successfully made map larger? */
|
||||
assoc = this->pop_free_assoc();
|
||||
}
|
||||
if ( assoc ) /* allocated new assoc without error? */
|
||||
{
|
||||
ref = mMap_Buckets + (hash % mMap_Slots);
|
||||
assoc->mAssoc_Next = *ref; /* link to prev bucket top */
|
||||
*ref = assoc; /* push assoc on top of bucket */
|
||||
|
||||
++mMap_Fill; /* one more member in the collection */
|
||||
++mMap_Seed; /* note the map has changed */
|
||||
}
|
||||
}
|
||||
if ( ref ) /* did not have an error during possible growth? */
|
||||
{
|
||||
mork_pos i = (*ref) - mMap_Assocs; /* index of assoc */
|
||||
if ( outPut && (outKey || outVal) ) /* copy old before cobbering? */
|
||||
this->get_assoc(outKey, outVal, i);
|
||||
|
||||
this->put_assoc(inKey, inVal, i);
|
||||
++mMap_Seed; /* note the map has changed */
|
||||
|
||||
if ( outChange )
|
||||
{
|
||||
if ( mMap_Changes )
|
||||
*outChange = mMap_Changes + i;
|
||||
else
|
||||
*outChange = this->FormDummyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadMapError(ev);
|
||||
|
||||
return outPut;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkMap::CutAll(morkEnv* ev)
|
||||
{
|
||||
mork_num outCutAll = 0;
|
||||
|
||||
if ( this->GoodMap() ) /* map looks good? */
|
||||
{
|
||||
mork_num slots = mMap_Slots;
|
||||
morkAssoc* before = mMap_Assocs - 1; /* before first member */
|
||||
morkAssoc* assoc = before + slots; /* the very last member */
|
||||
|
||||
++mMap_Seed; /* note the map is changed */
|
||||
|
||||
/* make the assoc array a linked list headed by first & tailed by last: */
|
||||
assoc->mAssoc_Next = 0; /* null terminate the new free list */
|
||||
while ( --assoc > before ) /* another assoc to link into the list? */
|
||||
assoc->mAssoc_Next = assoc + 1;
|
||||
mMap_FreeList = mMap_Assocs; /* all are free */
|
||||
|
||||
outCutAll = mMap_Fill; /* we'll cut all of them of course */
|
||||
|
||||
mMap_Fill = 0; /* the map is completely empty */
|
||||
}
|
||||
else this->NewBadMapError(ev);
|
||||
|
||||
return outCutAll;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkMap::Cut(morkEnv* ev, const void* inKey,
|
||||
void* outKey, void* outVal, mork_change** outChange)
|
||||
{
|
||||
mork_bool outCut = morkBool_kFalse;
|
||||
|
||||
if ( this->GoodMap() ) /* looks good? */
|
||||
{
|
||||
mork_u4 hash = this->Hash(ev, inKey);
|
||||
morkAssoc** ref = this->find(ev, inKey, hash);
|
||||
if ( ref ) /* found an assoc for key? */
|
||||
{
|
||||
outCut = morkBool_kTrue;
|
||||
morkAssoc* assoc = *ref;
|
||||
mork_pos i = assoc - mMap_Assocs; /* index of assoc */
|
||||
if ( outKey || outVal )
|
||||
this->get_assoc(outKey, outVal, i);
|
||||
|
||||
*ref = assoc->mAssoc_Next; /* unlink the found assoc */
|
||||
this->push_free_assoc(assoc); /* and put it in free list */
|
||||
|
||||
if ( outChange )
|
||||
{
|
||||
if ( mMap_Changes )
|
||||
*outChange = mMap_Changes + i;
|
||||
else
|
||||
*outChange = this->FormDummyChange();
|
||||
}
|
||||
|
||||
++mMap_Seed; /* note the map has changed */
|
||||
if ( mMap_Fill ) /* the count shows nonzero members? */
|
||||
--mMap_Fill; /* one less member in the collection */
|
||||
else
|
||||
this->NewSlotsUnderflowWarning(ev);
|
||||
}
|
||||
}
|
||||
else this->NewBadMapError(ev);
|
||||
|
||||
return outCut;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkMap::Get(morkEnv* ev, const void* inKey,
|
||||
void* outKey, void* outVal, mork_change** outChange)
|
||||
{
|
||||
mork_bool outGet = morkBool_kFalse;
|
||||
|
||||
if ( this->GoodMap() ) /* looks good? */
|
||||
{
|
||||
mork_u4 hash = this->Hash(ev, inKey);
|
||||
morkAssoc** ref = this->find(ev, inKey, hash);
|
||||
if ( ref ) /* found an assoc for inKey? */
|
||||
{
|
||||
mork_pos i = (*ref) - mMap_Assocs; /* index of assoc */
|
||||
outGet = morkBool_kTrue;
|
||||
this->get_assoc(outKey, outVal, i);
|
||||
if ( outChange )
|
||||
{
|
||||
if ( mMap_Changes )
|
||||
*outChange = mMap_Changes + i;
|
||||
else
|
||||
*outChange = this->FormDummyChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadMapError(ev);
|
||||
|
||||
return outGet;
|
||||
}
|
||||
|
||||
|
||||
morkMapIter::morkMapIter( )
|
||||
: mMapIter_Map( 0 )
|
||||
, mMapIter_Seed( 0 )
|
||||
|
||||
, mMapIter_Bucket( 0 )
|
||||
, mMapIter_AssocRef( 0 )
|
||||
, mMapIter_Assoc( 0 )
|
||||
, mMapIter_Next( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
morkMapIter::InitMapIter(morkEnv* ev, morkMap* ioMap)
|
||||
{
|
||||
mMapIter_Map = 0;
|
||||
mMapIter_Seed = 0;
|
||||
|
||||
mMapIter_Bucket = 0;
|
||||
mMapIter_AssocRef = 0;
|
||||
mMapIter_Assoc = 0;
|
||||
mMapIter_Next = 0;
|
||||
|
||||
if ( ioMap )
|
||||
{
|
||||
if ( ioMap->GoodMap() )
|
||||
{
|
||||
mMapIter_Map = ioMap;
|
||||
mMapIter_Seed = ioMap->mMap_Seed;
|
||||
}
|
||||
else ioMap->NewBadMapError(ev);
|
||||
}
|
||||
else ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkMapIter::morkMapIter(morkEnv* ev, morkMap* ioMap)
|
||||
: mMapIter_Map( 0 )
|
||||
, mMapIter_Seed( 0 )
|
||||
|
||||
, mMapIter_Bucket( 0 )
|
||||
, mMapIter_AssocRef( 0 )
|
||||
, mMapIter_Assoc( 0 )
|
||||
, mMapIter_Next( 0 )
|
||||
{
|
||||
if ( ioMap )
|
||||
{
|
||||
if ( ioMap->GoodMap() )
|
||||
{
|
||||
mMapIter_Map = ioMap;
|
||||
mMapIter_Seed = ioMap->mMap_Seed;
|
||||
}
|
||||
else ioMap->NewBadMapError(ev);
|
||||
}
|
||||
else ev->NilPointerError();
|
||||
}
|
||||
|
||||
void
|
||||
morkMapIter::CloseMapIter(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mMapIter_Map = 0;
|
||||
mMapIter_Seed = 0;
|
||||
|
||||
mMapIter_Bucket = 0;
|
||||
mMapIter_AssocRef = 0;
|
||||
mMapIter_Assoc = 0;
|
||||
mMapIter_Next = 0;
|
||||
}
|
||||
|
||||
mork_change*
|
||||
morkMapIter::First(morkEnv* ev, void* outKey, void* outVal)
|
||||
{
|
||||
mork_change* outFirst = 0;
|
||||
|
||||
morkMap* map = mMapIter_Map;
|
||||
|
||||
if ( map && map->GoodMap() ) /* map looks good? */
|
||||
{
|
||||
morkAssoc** bucket = map->mMap_Buckets;
|
||||
morkAssoc** end = bucket + map->mMap_Slots; /* one past last */
|
||||
|
||||
mMapIter_Seed = map->mMap_Seed; /* sync the seeds */
|
||||
|
||||
while ( bucket < end ) /* another bucket in which to look for assocs? */
|
||||
{
|
||||
morkAssoc* assoc = *bucket++;
|
||||
if ( assoc ) /* found the first map assoc in use? */
|
||||
{
|
||||
mork_pos i = assoc - map->mMap_Assocs;
|
||||
mork_change* c = map->mMap_Changes;
|
||||
outFirst = ( c )? (c + i) : map->FormDummyChange();
|
||||
|
||||
mMapIter_Assoc = assoc; /* current assoc in iteration */
|
||||
mMapIter_Next = assoc->mAssoc_Next; /* more in bucket */
|
||||
mMapIter_Bucket = --bucket; /* bucket for this assoc */
|
||||
mMapIter_AssocRef = bucket; /* slot referencing assoc */
|
||||
|
||||
map->get_assoc(outKey, outVal, i);
|
||||
|
||||
break; /* end while loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
else map->NewBadMapError(ev);
|
||||
|
||||
return outFirst;
|
||||
}
|
||||
|
||||
mork_change*
|
||||
morkMapIter::Next(morkEnv* ev, void* outKey, void* outVal)
|
||||
{
|
||||
mork_change* outNext = 0;
|
||||
|
||||
morkMap* map = mMapIter_Map;
|
||||
|
||||
if ( map && map->GoodMap() ) /* map looks good? */
|
||||
{
|
||||
if ( mMapIter_Seed == map->mMap_Seed ) /* in sync? */
|
||||
{
|
||||
morkAssoc* here = mMapIter_Assoc; /* current assoc */
|
||||
if ( here ) /* iteration is not yet concluded? */
|
||||
{
|
||||
morkAssoc* next = mMapIter_Next;
|
||||
morkAssoc* assoc = next; /* default new mMapIter_Assoc */
|
||||
if ( next ) /* there are more assocs in the same bucket after Here? */
|
||||
{
|
||||
morkAssoc** ref = mMapIter_AssocRef;
|
||||
|
||||
/* (*HereRef) equals Here, except when Here has been cut, after
|
||||
** which (*HereRef) always equals Next. So if (*HereRef) is not
|
||||
** equal to Next, then HereRef still needs to be updated to point
|
||||
** somewhere else other than Here. Otherwise it is fine.
|
||||
*/
|
||||
if ( *ref != next ) /* Here was not cut? must update HereRef? */
|
||||
mMapIter_AssocRef = &here->mAssoc_Next;
|
||||
|
||||
mMapIter_Next = next->mAssoc_Next;
|
||||
}
|
||||
else /* look for the next assoc in the next nonempty bucket */
|
||||
{
|
||||
morkAssoc** bucket = map->mMap_Buckets;
|
||||
morkAssoc** end = bucket + map->mMap_Slots; /* beyond */
|
||||
mMapIter_Assoc = 0; /* default to no more assocs */
|
||||
bucket = mMapIter_Bucket; /* last exhausted bucket */
|
||||
mMapIter_Assoc = 0; /* default to iteration ended */
|
||||
|
||||
while ( ++bucket < end ) /* another bucket to search for assocs? */
|
||||
{
|
||||
assoc = *bucket;
|
||||
if ( assoc ) /* found another map assoc in use? */
|
||||
{
|
||||
mMapIter_Bucket = bucket;
|
||||
mMapIter_AssocRef = bucket; /* ref to assoc */
|
||||
mMapIter_Next = assoc->mAssoc_Next; /* more */
|
||||
|
||||
break; /* end while loop */
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( assoc ) /* did we find another assoc in the iteration? */
|
||||
{
|
||||
mMapIter_Assoc = assoc; /* current assoc */
|
||||
mork_pos i = assoc - map->mMap_Assocs;
|
||||
mork_change* c = map->mMap_Changes;
|
||||
outNext = ( c )? (c + i) : map->FormDummyChange();
|
||||
|
||||
map->get_assoc( outKey, outVal, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else map->NewIterOutOfSyncError(ev);
|
||||
}
|
||||
else map->NewBadMapError(ev);
|
||||
|
||||
return outNext;
|
||||
}
|
||||
|
||||
mork_change*
|
||||
morkMapIter::Here(morkEnv* ev, void* outKey, void* outVal)
|
||||
{
|
||||
mork_change* outHere = 0;
|
||||
|
||||
morkMap* map = mMapIter_Map;
|
||||
|
||||
if ( map && map->GoodMap() ) /* map looks good? */
|
||||
{
|
||||
if ( mMapIter_Seed == map->mMap_Seed ) /* in sync? */
|
||||
{
|
||||
morkAssoc* here = mMapIter_Assoc; /* current assoc */
|
||||
if ( here ) /* iteration is not yet concluded? */
|
||||
{
|
||||
mork_pos i = here - map->mMap_Assocs;
|
||||
mork_change* c = map->mMap_Changes;
|
||||
outHere = ( c )? (c + i) : map->FormDummyChange();
|
||||
|
||||
map->get_assoc(outKey, outVal, i);
|
||||
}
|
||||
}
|
||||
else map->NewIterOutOfSyncError(ev);
|
||||
}
|
||||
else map->NewBadMapError(ev);
|
||||
|
||||
return outHere;
|
||||
}
|
||||
|
||||
mork_change*
|
||||
morkMapIter::CutHere(morkEnv* ev, void* outKey, void* outVal)
|
||||
{
|
||||
mork_change* outCutHere = 0;
|
||||
morkMap* map = mMapIter_Map;
|
||||
|
||||
if ( map && map->GoodMap() ) /* map looks good? */
|
||||
{
|
||||
if ( mMapIter_Seed == map->mMap_Seed ) /* in sync? */
|
||||
{
|
||||
morkAssoc* here = mMapIter_Assoc; /* current assoc */
|
||||
if ( here ) /* iteration is not yet concluded? */
|
||||
{
|
||||
morkAssoc** ref = mMapIter_AssocRef;
|
||||
if ( *ref != mMapIter_Next ) /* not already cut? */
|
||||
{
|
||||
mork_pos i = here - map->mMap_Assocs;
|
||||
mork_change* c = map->mMap_Changes;
|
||||
outCutHere = ( c )? (c + i) : map->FormDummyChange();
|
||||
if ( outKey || outVal )
|
||||
map->get_assoc(outKey, outVal, i);
|
||||
|
||||
map->push_free_assoc(here); /* add to free list */
|
||||
*ref = mMapIter_Next; /* unlink here from bucket list */
|
||||
|
||||
/* note the map has changed, but we are still in sync: */
|
||||
mMapIter_Seed = ++map->mMap_Seed; /* sync */
|
||||
|
||||
if ( map->mMap_Fill ) /* still has nonzero value? */
|
||||
--map->mMap_Fill; /* one less member in the collection */
|
||||
else
|
||||
map->NewSlotsUnderflowWarning(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
else map->NewIterOutOfSyncError(ev);
|
||||
}
|
||||
else map->NewBadMapError(ev);
|
||||
|
||||
return outCutHere;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,394 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#define _MORKMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/* (These hash methods closely resemble those in public domain IronDoc.) */
|
||||
|
||||
/*| Equal: equal for hash table. Note equal(a,b) implies hash(a)==hash(b).
|
||||
|*/
|
||||
typedef mork_bool (* morkMap_mEqual)
|
||||
(const morkMap* self, morkEnv* ev, const void* inKeyA, const void* inKeyB);
|
||||
|
||||
/*| Hash: hash for hash table. Note equal(a,b) implies hash(a)==hash(b).
|
||||
|*/
|
||||
typedef mork_u4 (* morkMap_mHash)
|
||||
(const morkMap* self, morkEnv* ev, const void* inKey);
|
||||
|
||||
/*| IsNil: whether a key slot contains a "null" value denoting "no such key".
|
||||
|*/
|
||||
typedef mork_bool (* morkMap_mIsNil)
|
||||
(const morkMap* self, morkEnv* ev, const void* inKey);
|
||||
|
||||
/*| Note: notify regarding a refcounting change for a key or a value.
|
||||
|*/
|
||||
//typedef void (* morkMap_mNote)
|
||||
//(morkMap* self, morkEnv* ev, void* inKeyOrVal);
|
||||
|
||||
/*| morkMapForm: slots need to initialize a new dict. (This is very similar
|
||||
**| to the config object for public domain IronDoc hash tables.)
|
||||
|*/
|
||||
class morkMapForm { // a struct of callback method pointers for morkMap
|
||||
public:
|
||||
|
||||
// const void* mMapForm_NilKey; // externally defined 'nil' bit pattern
|
||||
|
||||
// void* mMapForm_NilBuf[ 8 ]; // potential place to put NilKey
|
||||
// If keys are no larger than 8*sizeof(void*), NilKey can be put in NilBuf.
|
||||
// Note this should be true for all Mork subclasses, and we plan usage so.
|
||||
|
||||
// These three methods must always be provided, so zero will cause errors:
|
||||
|
||||
// morkMap_mEqual mMapForm_Equal; // for comparing two keys for identity
|
||||
// morkMap_mHash mMapForm_Hash; // deterministic key to hash method
|
||||
// morkMap_mIsNil mMapForm_IsNil; // to query whether a key equals 'nil'
|
||||
|
||||
// If any of these method slots are nonzero, then morkMap will call the
|
||||
// appropriate one to notify dict users when a key or value is added or cut.
|
||||
// Presumably a caller wants to know this in order to perform refcounting or
|
||||
// some other kind of memory management. These methods are definitely only
|
||||
// called when references to keys or values are inserted or removed, and are
|
||||
// never called when the actual number of references does not change (such
|
||||
// as when added keys are already present or cut keys are alreading missing).
|
||||
//
|
||||
// morkMap_mNote mMapForm_AddKey; // if nonzero, notify about add key
|
||||
// morkMap_mNote mMapForm_CutKey; // if nonzero, notify about cut key
|
||||
// morkMap_mNote mMapForm_AddVal; // if nonzero, notify about add val
|
||||
// morkMap_mNote mMapForm_CutVal; // if nonzero, notify about cut val
|
||||
//
|
||||
// These note methods have been removed because it seems difficult to
|
||||
// guarantee suitable alignment of objects passed to notification methods.
|
||||
|
||||
// Note dict clients should pick key and val sizes that provide whatever
|
||||
// alignment will be required for an array of such keys and values.
|
||||
mork_size mMapForm_KeySize; // size of every key (cannot be zero)
|
||||
mork_size mMapForm_ValSize; // size of every val (can indeed be zero)
|
||||
|
||||
mork_bool mMapForm_HoldChanges; // support changes array in the map
|
||||
mork_change mMapForm_DummyChange; // change used for false HoldChanges
|
||||
mork_bool mMapForm_KeyIsIP; // key is mork_ip sized
|
||||
mork_bool mMapForm_ValIsIP; // key is mork_ip sized
|
||||
};
|
||||
|
||||
/*| morkAssoc: a canonical association slot in a morkMap. A single assoc
|
||||
**| instance does nothing except point to the next assoc in the same bucket
|
||||
**| of a hash table. Each assoc has only two interesting attributes: 1) the
|
||||
**| address of the assoc, and 2) the next assoc in a bucket's list. The assoc
|
||||
**| address is interesting because in the context of an array of such assocs,
|
||||
**| one can determine the index of a particular assoc in the array by address
|
||||
**| arithmetic, subtracting the array address from the assoc address. And the
|
||||
**| index of each assoc is the same index as the associated key and val slots
|
||||
**| in the associated arrays
|
||||
**|
|
||||
**|| Think of an assoc instance as really also containing a key slot and a val
|
||||
**| slot, where each key is mMap_Form.mMapForm_KeySize bytes in size, and
|
||||
**| each val is mMap_Form.mMapForm_ValSize in size. But the key and val
|
||||
**| slots are stored in separate arrays with indexes that are parallel to the
|
||||
**| indexes in the array of morkAssoc instances. We have taken the variable
|
||||
**| sized slots out of the morkAssoc structure, and put them into parallel
|
||||
**| arrays associated with each morkAssoc by array index. And this leaves us
|
||||
**| with only the link field to the next assoc in each assoc instance.
|
||||
|*/
|
||||
class morkAssoc {
|
||||
public:
|
||||
morkAssoc* mAssoc_Next;
|
||||
};
|
||||
|
||||
|
||||
#define morkDerived_kMap /*i*/ 0x4D70 /* ascii 'Mp' */
|
||||
|
||||
#define morkMap_kTag /*i*/ 0x6D4D6150 /* ascii 'mMaP' */
|
||||
|
||||
/*| morkMap: a hash table based on the public domain IronDoc hash table
|
||||
**| (which is in turn rather like a similar OpenDoc hash table).
|
||||
|*/
|
||||
class morkMap : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
nsIMdbHeap* mMap_Heap; // strong ref to heap allocating all space
|
||||
mork_u4 mMap_Tag; // must equal morkMap_kTag
|
||||
|
||||
// When a morkMap instance is constructed, the dict form slots must be
|
||||
// provided in order to properly configure a dict with all runtime needs:
|
||||
|
||||
morkMapForm mMap_Form; // construction time parameterization
|
||||
|
||||
// Whenever the dict changes structure in a way that would affect any
|
||||
// iteration of the dict associations, the seed increments to show this:
|
||||
|
||||
mork_seed mMap_Seed; // counter for member and structural changes
|
||||
|
||||
// The current total assoc capacity of the dict is mMap_Slots, where
|
||||
// mMap_Fill of these slots are actually holding content, so mMap_Fill
|
||||
// is the actual membership count, and mMap_Slots is how larger membership
|
||||
// can become before the hash table must grow the buffers being used.
|
||||
|
||||
mork_count mMap_Slots; // count of slots in the hash table
|
||||
mork_fill mMap_Fill; // number of used slots in the hash table
|
||||
|
||||
// Key and value slots are bound to corresponding mMap_Assocs array slots.
|
||||
// Instead of having a single array like this: {key,val,next}[ mMap_Slots ]
|
||||
// we have instead three parallel arrays with essentially the same meaning:
|
||||
// {key}[ mMap_Slots ], {val}[ mMap_Slots ], {assocs}[ mMap_Slots ]
|
||||
|
||||
mork_u1* mMap_Keys; // mMap_Slots * mMapForm_KeySize buffer
|
||||
mork_u1* mMap_Vals; // mMap_Slots * mMapForm_ValSize buffer
|
||||
|
||||
// An assoc is "used" when it appears in a bucket's linked list of assocs.
|
||||
// Until an assoc is used, it appears in the FreeList linked list. Every
|
||||
// assoc that becomes used goes into the bucket determined by hashing the
|
||||
// key associated with a new assoc. The key associated with a new assoc
|
||||
// goes in to the slot in mMap_Keys which occupies exactly the same array
|
||||
// index as the array index of the used assoc in the mMap_Assocs array.
|
||||
|
||||
morkAssoc* mMap_Assocs; // mMap_Slots * sizeof(morkAssoc) buffer
|
||||
|
||||
// The changes array is only needed when the
|
||||
|
||||
mork_change* mMap_Changes; // mMap_Slots * sizeof(mork_change) buffer
|
||||
|
||||
// The Buckets array need not be the same length as the Assocs array, but we
|
||||
// usually do it that way so the average bucket depth is no more than one.
|
||||
// (We could pick a different policy, or make it parameterizable, but that's
|
||||
// tuning we can do some other time.)
|
||||
|
||||
morkAssoc** mMap_Buckets; // mMap_Slots * sizeof(morkAssoc*) buffer
|
||||
|
||||
// The length of the mMap_FreeList should equal (mMap_Slots - mMap_Fill).
|
||||
// We need a free list instead of a simpler representation because assocs
|
||||
// can be cut and returned to availability in any kind of unknown pattern.
|
||||
// (However, when assocs are first allocated, or when the dict is grown, we
|
||||
// know all new assocs are contiguous and can chain together adjacently.)
|
||||
|
||||
morkAssoc* mMap_FreeList; // list of unused mMap_Assocs array slots
|
||||
|
||||
public: // getters (morkProbeMap compatibility)
|
||||
mork_fill MapFill() const { return mMap_Fill; }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseMap() only if open
|
||||
virtual ~morkMap(); // assert that CloseMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkMap(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap,
|
||||
mork_size inKeySize, mork_size inValSize,
|
||||
mork_size inSlots, nsIMdbHeap* ioSlotHeap, mork_bool inHoldChanges);
|
||||
|
||||
void CloseMap(morkEnv* ev); // called by
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // poly map hash table methods
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const = 0;
|
||||
|
||||
virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Hash(morkEnv* ev, const void* inKey) const = 0;
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // open utitity methods
|
||||
|
||||
mork_bool GoodMapTag() const { return mMap_Tag == morkMap_kTag; }
|
||||
mork_bool GoodMap() const
|
||||
{ return ( IsNode() && GoodMapTag() ); }
|
||||
|
||||
void NewIterOutOfSyncError(morkEnv* ev);
|
||||
void NewBadMapError(morkEnv* ev);
|
||||
void NewSlotsUnderflowWarning(morkEnv* ev);
|
||||
void InitMap(morkEnv* ev, mork_size inSlots);
|
||||
|
||||
protected: // internal utitity methods
|
||||
|
||||
friend class morkMapIter;
|
||||
void clear_map(morkEnv* ev, nsIMdbHeap* ioHeap);
|
||||
|
||||
void* alloc(morkEnv* ev, mork_size inSize);
|
||||
void* clear_alloc(morkEnv* ev, mork_size inSize);
|
||||
|
||||
void push_free_assoc(morkAssoc* ioAssoc)
|
||||
{
|
||||
ioAssoc->mAssoc_Next = mMap_FreeList;
|
||||
mMap_FreeList = ioAssoc;
|
||||
}
|
||||
|
||||
morkAssoc* pop_free_assoc()
|
||||
{
|
||||
morkAssoc* assoc = mMap_FreeList;
|
||||
if ( assoc )
|
||||
mMap_FreeList = assoc->mAssoc_Next;
|
||||
return assoc;
|
||||
}
|
||||
|
||||
morkAssoc** find(morkEnv* ev, const void* inKey, mork_u4 inHash) const;
|
||||
|
||||
mork_u1* new_keys(morkEnv* ev, mork_num inSlots);
|
||||
mork_u1* new_values(morkEnv* ev, mork_num inSlots);
|
||||
mork_change* new_changes(morkEnv* ev, mork_num inSlots);
|
||||
morkAssoc** new_buckets(morkEnv* ev, mork_num inSlots);
|
||||
morkAssoc* new_assocs(morkEnv* ev, mork_num inSlots);
|
||||
mork_bool new_arrays(morkEnv* ev, morkHashArrays* old, mork_num inSlots);
|
||||
|
||||
mork_bool grow(morkEnv* ev);
|
||||
|
||||
void get_assoc(void* outKey, void* outVal, mork_pos inPos) const;
|
||||
void put_assoc(const void* inKey, const void* inVal, mork_pos inPos) const;
|
||||
|
||||
public: // inlines to form slots
|
||||
// const void* FormNilKey() const { return mMap_Form.mMapForm_NilKey; }
|
||||
|
||||
// morkMap_mEqual FormEqual() const { return mMap_Form.mMapForm_Equal; }
|
||||
// morkMap_mHash FormHash() const { return mMap_Form.mMapForm_Hash; }
|
||||
// orkMap_mIsNil FormIsNil() const { return mMap_Form.mMapForm_IsNil; }
|
||||
|
||||
// morkMap_mNote FormAddKey() const { return mMap_Form.mMapForm_AddKey; }
|
||||
// morkMap_mNote FormCutKey() const { return mMap_Form.mMapForm_CutKey; }
|
||||
// morkMap_mNote FormAddVal() const { return mMap_Form.mMapForm_AddVal; }
|
||||
// morkMap_mNote FormCutVal() const { return mMap_Form.mMapForm_CutVal; }
|
||||
|
||||
mork_size FormKeySize() const { return mMap_Form.mMapForm_KeySize; }
|
||||
mork_size FormValSize() const { return mMap_Form.mMapForm_ValSize; }
|
||||
|
||||
mork_bool FormKeyIsIP() const { return mMap_Form.mMapForm_KeyIsIP; }
|
||||
mork_bool FormValIsIP() const { return mMap_Form.mMapForm_ValIsIP; }
|
||||
|
||||
mork_bool FormHoldChanges() const
|
||||
{ return mMap_Form.mMapForm_HoldChanges; }
|
||||
|
||||
mork_change* FormDummyChange()
|
||||
{ return &mMap_Form.mMapForm_DummyChange; }
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool Put(morkEnv* ev, const void* inKey, const void* inVal,
|
||||
void* outKey, void* outVal, mork_change** outChange);
|
||||
|
||||
mork_bool Cut(morkEnv* ev, const void* inKey,
|
||||
void* outKey, void* outVal, mork_change** outChange);
|
||||
|
||||
mork_bool Get(morkEnv* ev, const void* inKey,
|
||||
void* outKey, void* outVal, mork_change** outChange);
|
||||
|
||||
mork_num CutAll(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkMap(const morkMap& other);
|
||||
morkMap& operator=(const morkMap& other);
|
||||
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
/*| morkMapIter: an iterator for morkMap and subclasses. This is not a node,
|
||||
**| and expected usage is as a member of some other node subclass, such as in
|
||||
**| a cursor subclass or a thumb subclass. Also, iters might be as temp stack
|
||||
**| objects when scanning the content of a map.
|
||||
|*/
|
||||
class morkMapIter{ // iterator for hash table map
|
||||
|
||||
protected:
|
||||
morkMap* mMapIter_Map; // map to iterate, NOT refcounted
|
||||
mork_seed mMapIter_Seed; // cached copy of map's seed
|
||||
|
||||
morkAssoc** mMapIter_Bucket; // one bucket in mMap_Buckets array
|
||||
morkAssoc** mMapIter_AssocRef; // usually *AtRef equals Here
|
||||
morkAssoc* mMapIter_Assoc; // the current assoc in an iteration
|
||||
morkAssoc* mMapIter_Next; // mMapIter_Assoc->mAssoc_Next */
|
||||
|
||||
public:
|
||||
morkMapIter(morkEnv* ev, morkMap* ioMap);
|
||||
void CloseMapIter(morkEnv* ev);
|
||||
|
||||
morkMapIter( ); // everything set to zero -- need to call InitMapIter()
|
||||
|
||||
protected: // we want all subclasses to provide typesafe wrappers:
|
||||
|
||||
void InitMapIter(morkEnv* ev, morkMap* ioMap);
|
||||
|
||||
// The morkAssoc returned below is always either mork_change* or
|
||||
// else nil (when there is no such assoc). We return a pointer to
|
||||
// the change rather than a simple bool, because callers might
|
||||
// want to access change info associated with an assoc.
|
||||
|
||||
mork_change* First(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Next(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Here(morkEnv* ev, void* outKey, void* outVal);
|
||||
|
||||
mork_change* CutHere(morkEnv* ev, void* outKey, void* outVal);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKMAP_ */
|
|
@ -0,0 +1,687 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKHANDLE_
|
||||
#include "morkHandle.h"
|
||||
#endif
|
||||
|
||||
/*3456789_123456789_123456789_123456789_123456789_123456789_123456789_12345678*/
|
||||
|
||||
/* ===== ===== ===== ===== morkUsage ===== ===== ===== ===== */
|
||||
|
||||
static morkUsage morkUsage_gHeap; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kHeap = morkUsage_gHeap;
|
||||
|
||||
static morkUsage morkUsage_gStack; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kStack = morkUsage_gStack;
|
||||
|
||||
static morkUsage morkUsage_gMember; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kMember = morkUsage_gMember;
|
||||
|
||||
static morkUsage morkUsage_gGlobal; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kGlobal = morkUsage_gGlobal;
|
||||
|
||||
static morkUsage morkUsage_gPool; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kPool = morkUsage_gPool;
|
||||
|
||||
static morkUsage morkUsage_gNone; // ensure EnsureReadyStaticUsage()
|
||||
const morkUsage& morkUsage::kNone = morkUsage_gNone;
|
||||
|
||||
// This must be structured to allow for non-zero values in global variables
|
||||
// just before static init time. We can only safely check for whether a
|
||||
// global has the address of some other global. Please, do not initialize
|
||||
// either of the variables below to zero, because this could break when a zero
|
||||
// is assigned at static init time, but after EnsureReadyStaticUsage() runs.
|
||||
|
||||
static mork_u4 morkUsage_g_static_init_target; // only address of this matters
|
||||
static mork_u4* morkUsage_g_static_init_done; // is address of target above?
|
||||
|
||||
#define morkUsage_do_static_init() \
|
||||
( morkUsage_g_static_init_done = &morkUsage_g_static_init_target )
|
||||
|
||||
#define morkUsage_need_static_init() \
|
||||
( morkUsage_g_static_init_done != &morkUsage_g_static_init_target )
|
||||
|
||||
/*static*/
|
||||
void morkUsage::EnsureReadyStaticUsage()
|
||||
{
|
||||
if ( morkUsage_need_static_init() )
|
||||
{
|
||||
morkUsage_do_static_init();
|
||||
|
||||
morkUsage_gHeap.InitUsage(morkUsage_kHeap);
|
||||
morkUsage_gStack.InitUsage(morkUsage_kStack);
|
||||
morkUsage_gMember.InitUsage(morkUsage_kMember);
|
||||
morkUsage_gGlobal.InitUsage(morkUsage_kGlobal);
|
||||
morkUsage_gPool.InitUsage(morkUsage_kPool);
|
||||
morkUsage_gNone.InitUsage(morkUsage_kNone);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetHeap() // kHeap safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gHeap;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetStack() // kStack safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gStack;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetMember() // kMember safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gMember;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetGlobal() // kGlobal safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gGlobal;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetPool() // kPool safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gPool;
|
||||
}
|
||||
|
||||
/*static*/
|
||||
const morkUsage& morkUsage::GetNone() // kNone safe at static init time
|
||||
{
|
||||
EnsureReadyStaticUsage();
|
||||
return morkUsage_gNone;
|
||||
}
|
||||
|
||||
morkUsage::morkUsage()
|
||||
{
|
||||
if ( morkUsage_need_static_init() )
|
||||
{
|
||||
morkUsage::EnsureReadyStaticUsage();
|
||||
}
|
||||
}
|
||||
|
||||
morkUsage::morkUsage(mork_usage code)
|
||||
: mUsage_Code(code)
|
||||
{
|
||||
if ( morkUsage_need_static_init() )
|
||||
{
|
||||
morkUsage::EnsureReadyStaticUsage();
|
||||
}
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*static*/ void*
|
||||
morkNode::MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
|
||||
{
|
||||
void* node = 0;
|
||||
if ( &ioHeap )
|
||||
{
|
||||
ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void **) &node);
|
||||
if ( !node )
|
||||
ev->OutOfMemoryError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkNode::ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap)
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mork_usage usage = mNode_Usage; // mNode_Usage before ~morkNode
|
||||
this->morkNode::~morkNode(); // first call polymorphic destructor
|
||||
if ( ioHeap ) // was this node heap allocated?
|
||||
ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
else if ( usage == morkUsage_kPool ) // mNode_Usage before ~morkNode
|
||||
{
|
||||
morkHandle* h = (morkHandle*) this;
|
||||
if ( h->IsHandle() && h->GoodHandleTag() )
|
||||
{
|
||||
if ( h->mHandle_Face )
|
||||
{
|
||||
if (ev->mEnv_HandlePool)
|
||||
ev->mEnv_HandlePool->ZapHandle(ev, h->mHandle_Face);
|
||||
else if (h->mHandle_Env && h->mHandle_Env->mEnv_HandlePool)
|
||||
h->mHandle_Env->mEnv_HandlePool->ZapHandle(ev, h->mHandle_Face);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*public virtual*/ void
|
||||
morkNode::CloseMorkNode(morkEnv* ev) // CloseNode() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseNode(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkNode::CloseMdbObject(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CloseMdbObject((morkEnv *) mev);
|
||||
}
|
||||
|
||||
mdb_err morkNode::CloseMdbObject(morkEnv *ev)
|
||||
{
|
||||
// if only one ref, Handle_CutStrongRef will clean up better.
|
||||
if (mNode_Uses == 1)
|
||||
return CutStrongRef(ev);
|
||||
|
||||
mdb_err outErr = 0;
|
||||
|
||||
if ( IsNode() && IsOpenNode() )
|
||||
{
|
||||
if ( ev )
|
||||
{
|
||||
CloseMorkNode(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkNode::~morkNode() // assert that CloseNode() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode() || IsDeadNode()); // sometimes we call destructor explictly w/o freeing object.
|
||||
mNode_Access = morkAccess_kDead;
|
||||
mNode_Usage = morkUsage_kNone;
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
// void CloseMorkNode(morkEnv* ev) = 0; // CloseNode() only if open
|
||||
// CloseMorkNode() is the polymorphic close method called when uses==0,
|
||||
// which must do NOTHING at all when IsOpenNode() is not true. Otherwise,
|
||||
// CloseMorkNode() should call a static close method specific to an object.
|
||||
// Each such static close method should either call inherited static close
|
||||
// methods, or else perform the consolidated effect of calling them, where
|
||||
// subclasses should closely track any changes in base classes with care.
|
||||
|
||||
|
||||
/*public non-poly*/
|
||||
morkNode::morkNode( mork_usage inCode )
|
||||
: mNode_Heap( 0 )
|
||||
, mNode_Base( morkBase_kNode )
|
||||
, mNode_Derived ( 0 ) // until subclass sets appropriately
|
||||
, mNode_Access( morkAccess_kOpen )
|
||||
, mNode_Usage( inCode )
|
||||
, mNode_Mutable( morkAble_kEnabled )
|
||||
, mNode_Load( morkLoad_kClean )
|
||||
, mNode_Uses( 1 )
|
||||
, mNode_Refs( 1 )
|
||||
{
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkNode::morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
||||
: mNode_Heap( ioHeap )
|
||||
, mNode_Base( morkBase_kNode )
|
||||
, mNode_Derived ( 0 ) // until subclass sets appropriately
|
||||
, mNode_Access( morkAccess_kOpen )
|
||||
, mNode_Usage( inUsage.Code() )
|
||||
, mNode_Mutable( morkAble_kEnabled )
|
||||
, mNode_Load( morkLoad_kClean )
|
||||
, mNode_Uses( 1 )
|
||||
, mNode_Refs( 1 )
|
||||
{
|
||||
if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
|
||||
MORK_ASSERT(ioHeap);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkNode::morkNode(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
||||
: mNode_Heap( ioHeap )
|
||||
, mNode_Base( morkBase_kNode )
|
||||
, mNode_Derived ( 0 ) // until subclass sets appropriately
|
||||
, mNode_Access( morkAccess_kOpen )
|
||||
, mNode_Usage( inUsage.Code() )
|
||||
, mNode_Mutable( morkAble_kEnabled )
|
||||
, mNode_Load( morkLoad_kClean )
|
||||
, mNode_Uses( 1 )
|
||||
, mNode_Refs( 1 )
|
||||
{
|
||||
if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
|
||||
{
|
||||
this->NilHeapError(ev);
|
||||
}
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::RefsUnderUsesWarning(morkEnv* ev) const
|
||||
{
|
||||
ev->NewError("mNode_Refs < mNode_Uses");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::NonNodeError(morkEnv* ev) const // called when IsNode() is false
|
||||
{
|
||||
ev->NewError("non-morkNode");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::NonOpenNodeError(morkEnv* ev) const // when IsOpenNode() is false
|
||||
{
|
||||
ev->NewError("non-open-morkNode");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::NonMutableNodeError(morkEnv* ev) const // when IsMutable() is false
|
||||
{
|
||||
ev->NewError("non-mutable-morkNode");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::NilHeapError(morkEnv* ev) const // zero mNode_Heap w/ kHeap usage
|
||||
{
|
||||
ev->NewError("nil mNode_Heap");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::RefsOverflowWarning(morkEnv* ev) const // mNode_Refs overflow
|
||||
{
|
||||
ev->NewWarning("mNode_Refs overflow");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::UsesOverflowWarning(morkEnv* ev) const // mNode_Uses overflow
|
||||
{
|
||||
ev->NewWarning("mNode_Uses overflow");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::RefsUnderflowWarning(morkEnv* ev) const // mNode_Refs underflow
|
||||
{
|
||||
ev->NewWarning("mNode_Refs underflow");
|
||||
}
|
||||
|
||||
/*protected non-poly*/ void
|
||||
morkNode::UsesUnderflowWarning(morkEnv* ev) const // mNode_Uses underflow
|
||||
{
|
||||
ev->NewWarning("mNode_Uses underflow");
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
this->MarkShut();
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbCompare_SlotStrongCompare(nsIMdbCompare* self, morkEnv* ev,
|
||||
nsIMdbCompare** ioSlot)
|
||||
// If *ioSlot is non-nil, that compare is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbCompare* compare = *ioSlot;
|
||||
if ( self != compare )
|
||||
{
|
||||
if ( compare )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
compare->CutStrongRef(menv);
|
||||
}
|
||||
if ( self && ev->Good() && (self->AddStrongRef(menv)==0) && ev->Good() )
|
||||
*ioSlot = self;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot)
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbFile* file = *ioSlot;
|
||||
if ( self != file )
|
||||
{
|
||||
if ( file )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
NS_RELEASE(file);
|
||||
}
|
||||
if ( self && ev->Good() && (NS_ADDREF(self)>=0) && ev->Good() )
|
||||
*ioSlot = self;
|
||||
}
|
||||
}
|
||||
|
||||
void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot)
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, self is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we
|
||||
// permit expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
{
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
nsIMdbHeap* heap = *ioSlot;
|
||||
if ( self != heap )
|
||||
{
|
||||
if ( heap )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
heap->HeapCutStrongRef(menv);
|
||||
}
|
||||
if ( self && ev->Good() && (self->HeapAddStrongRef(menv)==0) && ev->Good() )
|
||||
*ioSlot = self;
|
||||
}
|
||||
}
|
||||
|
||||
/*public static*/ void
|
||||
morkNode::SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot)
|
||||
// If *ioSlot is non-nil, that node is released by CutStrongRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if positive is returned to show success,
|
||||
// then me is put into slot *ioSlot. Note me can be nil, so we take
|
||||
// expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
|
||||
{
|
||||
morkNode* node = *ioSlot;
|
||||
if ( me != node )
|
||||
{
|
||||
if ( node )
|
||||
{
|
||||
// what if this nulls out the ev and causes asserts?
|
||||
// can we move this after the CutStrongRef()?
|
||||
*ioSlot = 0;
|
||||
node->CutStrongRef(ev);
|
||||
}
|
||||
if ( me && me->AddStrongRef(ev) )
|
||||
*ioSlot = me;
|
||||
}
|
||||
}
|
||||
|
||||
/*public static*/ void
|
||||
morkNode::SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot)
|
||||
// If *ioSlot is non-nil, that node is released by CutWeakRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// calling AddWeakRef(), and if positive is returned to show success,
|
||||
// then me is put into slot *ioSlot. Note me can be nil, so we
|
||||
// expression 'morkNode::SlotWeakNode((morkNode*) 0, ev, &slot)'.
|
||||
{
|
||||
morkNode* node = *ioSlot;
|
||||
if ( me != node )
|
||||
{
|
||||
if ( node )
|
||||
{
|
||||
*ioSlot = 0;
|
||||
node->CutWeakRef(ev);
|
||||
}
|
||||
if ( me && me->AddWeakRef(ev) )
|
||||
*ioSlot = me;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ mork_uses
|
||||
morkNode::AddStrongRef(morkEnv* ev)
|
||||
{
|
||||
mork_uses outUses = 0;
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mork_uses uses = mNode_Uses;
|
||||
mork_refs refs = mNode_Refs;
|
||||
if ( refs < uses ) // need to fix broken refs/uses relation?
|
||||
{
|
||||
this->RefsUnderUsesWarning(ev);
|
||||
mNode_Refs = mNode_Uses = refs = uses;
|
||||
}
|
||||
if ( refs < morkNode_kMaxRefCount ) // not too great?
|
||||
{
|
||||
mNode_Refs = ++refs;
|
||||
mNode_Uses = ++uses;
|
||||
}
|
||||
else
|
||||
this->RefsOverflowWarning(ev);
|
||||
|
||||
outUses = uses;
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
return outUses;
|
||||
}
|
||||
|
||||
/*private non-poly*/ mork_bool
|
||||
morkNode::cut_use_count(morkEnv* ev) // just one part of CutStrongRef()
|
||||
{
|
||||
mork_bool didCut = morkBool_kFalse;
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mork_uses uses = mNode_Uses;
|
||||
if ( uses ) // not yet zero?
|
||||
mNode_Uses = --uses;
|
||||
else
|
||||
this->UsesUnderflowWarning(ev);
|
||||
|
||||
didCut = morkBool_kTrue;
|
||||
if ( !mNode_Uses ) // last use gone? time to close node?
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
if ( !mNode_Refs ) // no outstanding reference?
|
||||
{
|
||||
this->RefsUnderflowWarning(ev);
|
||||
++mNode_Refs; // prevent potential crash during close
|
||||
}
|
||||
this->CloseMorkNode(ev); // polymorphic self close
|
||||
// (Note CutNode() is not polymorphic -- so don't call that.)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
return didCut;
|
||||
}
|
||||
|
||||
/*public non-poly*/ mork_uses
|
||||
morkNode::CutStrongRef(morkEnv* ev)
|
||||
{
|
||||
mork_refs outRefs = 0;
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( this->cut_use_count(ev) )
|
||||
outRefs = this->CutWeakRef(ev);
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
return outRefs;
|
||||
}
|
||||
|
||||
/*public non-poly*/ mork_refs
|
||||
morkNode::AddWeakRef(morkEnv* ev)
|
||||
{
|
||||
mork_refs outRefs = 0;
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mork_refs refs = mNode_Refs;
|
||||
if ( refs < morkNode_kMaxRefCount ) // not too great?
|
||||
mNode_Refs = ++refs;
|
||||
else
|
||||
this->RefsOverflowWarning(ev);
|
||||
|
||||
outRefs = refs;
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
return outRefs;
|
||||
}
|
||||
|
||||
/*public non-poly*/ mork_refs
|
||||
morkNode::CutWeakRef(morkEnv* ev)
|
||||
{
|
||||
mork_refs outRefs = 0;
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mork_uses uses = mNode_Uses;
|
||||
mork_refs refs = mNode_Refs;
|
||||
if ( refs ) // not yet zero?
|
||||
mNode_Refs = --refs;
|
||||
else
|
||||
this->RefsUnderflowWarning(ev);
|
||||
|
||||
if ( refs < uses ) // need to fix broken refs/uses relation?
|
||||
{
|
||||
this->RefsUnderUsesWarning(ev);
|
||||
mNode_Refs = mNode_Uses = refs = uses;
|
||||
}
|
||||
|
||||
outRefs = refs;
|
||||
if ( !refs ) // last reference gone? time to destroy node?
|
||||
this->ZapOld(ev, mNode_Heap); // self destroy, use this no longer
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
return outRefs;
|
||||
}
|
||||
|
||||
static const char morkNode_kBroken[] = "broken";
|
||||
|
||||
/*public non-poly*/ const char*
|
||||
morkNode::GetNodeAccessAsString() const // e.g. "open", "shut", etc.
|
||||
{
|
||||
const char* outString = morkNode_kBroken;
|
||||
switch( mNode_Access )
|
||||
{
|
||||
case morkAccess_kOpen: outString = "open"; break;
|
||||
case morkAccess_kClosing: outString = "closing"; break;
|
||||
case morkAccess_kShut: outString = "shut"; break;
|
||||
case morkAccess_kDead: outString = "dead"; break;
|
||||
}
|
||||
return outString;
|
||||
}
|
||||
|
||||
/*public non-poly*/ const char*
|
||||
morkNode::GetNodeUsageAsString() const // e.g. "heap", "stack", etc.
|
||||
{
|
||||
const char* outString = morkNode_kBroken;
|
||||
switch( mNode_Usage )
|
||||
{
|
||||
case morkUsage_kHeap: outString = "heap"; break;
|
||||
case morkUsage_kStack: outString = "stack"; break;
|
||||
case morkUsage_kMember: outString = "member"; break;
|
||||
case morkUsage_kGlobal: outString = "global"; break;
|
||||
case morkUsage_kPool: outString = "pool"; break;
|
||||
case morkUsage_kNone: outString = "none"; break;
|
||||
}
|
||||
return outString;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,301 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#define _MORKNODE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkUsage_kHeap 'h'
|
||||
#define morkUsage_kStack 's'
|
||||
#define morkUsage_kMember 'm'
|
||||
#define morkUsage_kGlobal 'g'
|
||||
#define morkUsage_kPool 'p'
|
||||
#define morkUsage_kNone 'n'
|
||||
|
||||
class morkUsage {
|
||||
public:
|
||||
mork_usage mUsage_Code; // kHeap, kStack, kMember, or kGhost
|
||||
|
||||
public:
|
||||
morkUsage(mork_usage inCode);
|
||||
|
||||
morkUsage(); // does nothing except maybe call EnsureReadyStaticUsage()
|
||||
void InitUsage( mork_usage inCode)
|
||||
{ mUsage_Code = inCode; }
|
||||
|
||||
~morkUsage() { }
|
||||
mork_usage Code() const { return mUsage_Code; }
|
||||
|
||||
static void EnsureReadyStaticUsage();
|
||||
|
||||
public:
|
||||
static const morkUsage& kHeap; // morkUsage_kHeap
|
||||
static const morkUsage& kStack; // morkUsage_kStack
|
||||
static const morkUsage& kMember; // morkUsage_kMember
|
||||
static const morkUsage& kGlobal; // morkUsage_kGlobal
|
||||
static const morkUsage& kPool; // morkUsage_kPool
|
||||
static const morkUsage& kNone; // morkUsage_kNone
|
||||
|
||||
static const morkUsage& GetHeap(); // kHeap, safe at static init time
|
||||
static const morkUsage& GetStack(); // kStack, safe at static init time
|
||||
static const morkUsage& GetMember(); // kMember, safe at static init time
|
||||
static const morkUsage& GetGlobal(); // kGlobal, safe at static init time
|
||||
static const morkUsage& GetPool(); // kPool, safe at static init time
|
||||
static const morkUsage& GetNone(); // kNone, safe at static init time
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */
|
||||
|
||||
#define morkBase_kNode /*i*/ 0x4E64 /* ascii 'Nd' */
|
||||
|
||||
/*| morkNode: several groups of two-byte integers that track the basic
|
||||
**| status of an object that can be used to compose in-memory graphs.
|
||||
**| This is the base class for nsIMdbObject (which adds members that fit
|
||||
**| the needs of an nsIMdbObject subclass). The morkNode class is also used
|
||||
**| as the base class for other Mork db classes with no strong relation to
|
||||
**| the MDB class hierarchy.
|
||||
**|
|
||||
**|| Heap: the heap in which this node was allocated, when the usage equals
|
||||
**| morkUsage_kHeap to show dynamic allocation. Note this heap is NOT ref-
|
||||
**| counted, because that would be too great and complex a burden for all
|
||||
**| the nodes allocated in that heap. So heap users should take care to
|
||||
**| understand that nodes allocated in that heap are considered protected
|
||||
**| by some inclusive context in which all those nodes are allocated, and
|
||||
**| that context must maintain at least one strong refcount for the heap.
|
||||
**| Occasionally a node subclass will indeed wish to hold a refcounted
|
||||
**| reference to a heap, and possibly the same heap that is in mNode_Heap,
|
||||
**| but this is always done in a separate slot that explicitly refcounts,
|
||||
**| so we avoid confusing what is meant by the mNode_Heap slot.
|
||||
|*/
|
||||
class morkNode /*: public nsISupports */ { // base class for constructing Mork object graphs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
// NS_DECL_ISUPPORTS;
|
||||
nsIMdbHeap* mNode_Heap; // NON-refcounted heap pointer
|
||||
|
||||
mork_base mNode_Base; // must equal morkBase_kNode
|
||||
mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
mork_able mNode_Mutable; // can this node be modified?
|
||||
mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
mork_uses mNode_Uses; // refcount for strong refs
|
||||
mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
protected: // special case empty construction for morkHandleFrame
|
||||
friend class morkHandleFrame;
|
||||
morkNode() { }
|
||||
|
||||
public: // inlines for weird mNode_Mutable and mNode_Load constants
|
||||
|
||||
void SetFrozen() { mNode_Mutable = morkAble_kDisabled; }
|
||||
void SetMutable() { mNode_Mutable = morkAble_kEnabled; }
|
||||
void SetAsleep() { mNode_Mutable = morkAble_kAsleep; }
|
||||
|
||||
mork_bool IsFrozen() const { return mNode_Mutable == morkAble_kDisabled; }
|
||||
mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; }
|
||||
mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; }
|
||||
|
||||
void SetNodeClean() { mNode_Load = morkLoad_kClean; }
|
||||
void SetNodeDirty() { mNode_Load = morkLoad_kDirty; }
|
||||
|
||||
mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; }
|
||||
mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; }
|
||||
|
||||
public: // morkNode memory management methods
|
||||
static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
|
||||
|
||||
void ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap); // replaces operator delete()
|
||||
// this->morkNode::~morkNode(); // first call polymorphic destructor
|
||||
// if ( ioHeap ) // was this node heap allocated?
|
||||
// ioHeap->Free(ev->AsMdbEnv(), this);
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
|
||||
protected: // construction without an anv needed for first env constructed:
|
||||
morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap);
|
||||
|
||||
morkNode(mork_usage inCode); // usage == inCode, heap == nil
|
||||
|
||||
// { ===== begin basic node interface =====
|
||||
public: // morkNode virtual methods
|
||||
// virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream);
|
||||
// virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream);
|
||||
|
||||
virtual ~morkNode(); // assert that CloseNode() executed earlier
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseNode() only if open
|
||||
|
||||
// CloseMorkNode() is the polymorphic close method called when uses==0,
|
||||
// which must do NOTHING at all when IsOpenNode() is not true. Otherwise,
|
||||
// CloseMorkNode() should call a static close method specific to an object.
|
||||
// Each such static close method should either call inherited static close
|
||||
// methods, or else perform the consolidated effect of calling them, where
|
||||
// subclasses should closely track any changes in base classes with care.
|
||||
|
||||
public: // morkNode construction
|
||||
morkNode(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
|
||||
void CloseNode(morkEnv* ev); // called by CloseMorkNode();
|
||||
mdb_err CloseMdbObject(morkEnv *ev);
|
||||
NS_IMETHOD CloseMdbObject(nsIMdbEnv *ev);
|
||||
private: // copying is not allowed
|
||||
morkNode(const morkNode& other);
|
||||
morkNode& operator=(const morkNode& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsNode() const
|
||||
{ return mNode_Base == morkBase_kNode; }
|
||||
// } ===== end basic node methods =====
|
||||
|
||||
public: // public error & warning methods
|
||||
|
||||
void RefsUnderUsesWarning(morkEnv* ev) const; // call if mNode_Refs < mNode_Uses
|
||||
void NonNodeError(morkEnv* ev) const; // call when IsNode() is false
|
||||
void NilHeapError(morkEnv* ev) const; // zero mNode_Heap when usage is kHeap
|
||||
void NonOpenNodeError(morkEnv* ev) const; // call when IsOpenNode() is false
|
||||
|
||||
void NonMutableNodeError(morkEnv* ev) const; // when IsMutable() is false
|
||||
|
||||
void RefsOverflowWarning(morkEnv* ev) const; // call on mNode_Refs overflow
|
||||
void UsesOverflowWarning(morkEnv* ev) const; // call on mNode_Uses overflow
|
||||
void RefsUnderflowWarning(morkEnv* ev) const; // call on mNode_Refs underflow
|
||||
void UsesUnderflowWarning(morkEnv* ev) const; // call on mNode_Uses underflow
|
||||
|
||||
private: // private refcounting methods
|
||||
mork_bool cut_use_count(morkEnv* ev); // just one part of CutStrongRef()
|
||||
|
||||
public: // other morkNode methods
|
||||
|
||||
mork_bool GoodRefs() const { return mNode_Refs >= mNode_Uses; }
|
||||
mork_bool BadRefs() const { return mNode_Refs < mNode_Uses; }
|
||||
|
||||
mork_uses StrongRefsOnly() const { return mNode_Uses; }
|
||||
mork_refs WeakRefsOnly() const { return (mork_refs) ( mNode_Refs - mNode_Uses ); }
|
||||
|
||||
// (this refcounting derives from public domain IronDoc node refcounts)
|
||||
virtual mork_refs AddStrongRef(morkEnv* ev);
|
||||
virtual mork_refs CutStrongRef(morkEnv* ev);
|
||||
mork_refs AddWeakRef(morkEnv* ev);
|
||||
mork_refs CutWeakRef(morkEnv* ev);
|
||||
|
||||
const char* GetNodeAccessAsString() const; // e.g. "open", "shut", etc.
|
||||
const char* GetNodeUsageAsString() const; // e.g. "heap", "stack", etc.
|
||||
|
||||
mork_usage NodeUsage() const { return mNode_Usage; }
|
||||
|
||||
mork_bool IsHeapNode() const
|
||||
{ return mNode_Usage == morkUsage_kHeap; }
|
||||
|
||||
mork_bool IsOpenNode() const
|
||||
{ return mNode_Access == morkAccess_kOpen; }
|
||||
|
||||
mork_bool IsShutNode() const
|
||||
{ return mNode_Access == morkAccess_kShut; }
|
||||
|
||||
mork_bool IsDeadNode() const
|
||||
{ return mNode_Access == morkAccess_kDead; }
|
||||
|
||||
mork_bool IsClosingNode() const
|
||||
{ return mNode_Access == morkAccess_kClosing; }
|
||||
|
||||
mork_bool IsOpenOrClosingNode() const
|
||||
{ return IsOpenNode() || IsClosingNode(); }
|
||||
|
||||
mork_bool HasNodeAccess() const
|
||||
{ return ( IsOpenNode() || IsShutNode() || IsClosingNode() ); }
|
||||
|
||||
void MarkShut() { mNode_Access = morkAccess_kShut; }
|
||||
void MarkClosing() { mNode_Access = morkAccess_kClosing; }
|
||||
void MarkDead() { mNode_Access = morkAccess_kDead; }
|
||||
|
||||
public: // refcounting for typesafe subclass inline methods
|
||||
static void SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
|
||||
// If *ioSlot is non-nil, that node is released by CutWeakRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// calling AddWeakRef(), and if positive is returned to show success,
|
||||
// then this is put into slot *ioSlot. Note me can be nil, so we
|
||||
// permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'.
|
||||
|
||||
static void SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
|
||||
// If *ioSlot is non-nil, that node is released by CutStrongRef() and
|
||||
// then zeroed out. Then if me is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if positive is returned to show success,
|
||||
// then me is put into slot *ioSlot. Note me can be nil, so we take
|
||||
// expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
|
||||
};
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot);
|
||||
// If *ioSlot is non-nil, that heap is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot);
|
||||
// If *ioSlot is non-nil, that file is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
|
||||
|
||||
extern void // utility method very similar to morkNode::SlotStrongNode():
|
||||
nsIMdbCompare_SlotStrongCompare(nsIMdbCompare* self, morkEnv* ev,
|
||||
nsIMdbCompare** ioSlot);
|
||||
// If *ioSlot is non-nil, that compare is released by CutStrongRef() and
|
||||
// then zeroed out. Then if self is non-nil, this is acquired by
|
||||
// calling AddStrongRef(), and if the return value shows success,
|
||||
// then self is put into slot *ioSlot. Note self can be nil, so we take
|
||||
// expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKNODE_ */
|
|
@ -0,0 +1,192 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#include "morkIntMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkNodeMap::CloseMorkNode(morkEnv* ev) // CloseNodeMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseNodeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkNodeMap::~morkNodeMap() // assert CloseNodeMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkNodeMap::morkNodeMap(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkIntMap(ev, inUsage, /*valsize*/ sizeof(morkNode*), ioHeap, ioSlotHeap,
|
||||
/*inHoldChanges*/ morkBool_kTrue)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kNodeMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkNodeMap::CloseNodeMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CutAllNodes(ev);
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
mork_bool
|
||||
morkNodeMap::AddNode(morkEnv* ev, mork_token inToken, morkNode* ioNode)
|
||||
// the AddNode() method return value equals ev->Good().
|
||||
{
|
||||
if ( ioNode && ev->Good() )
|
||||
{
|
||||
morkNode* node = 0; // old val in the map
|
||||
|
||||
mork_bool put = this->Put(ev, &inToken, &ioNode,
|
||||
/*key*/ (void*) 0, &node, (mork_change**) 0);
|
||||
|
||||
if ( put ) // replaced an existing value for key inToken?
|
||||
{
|
||||
if ( node && node != ioNode ) // need to release old node?
|
||||
node->CutStrongRef(ev);
|
||||
}
|
||||
|
||||
if ( ev->Bad() || !ioNode->AddStrongRef(ev) )
|
||||
{
|
||||
// problems adding node or increasing refcount?
|
||||
this->Cut(ev, &inToken, // make sure not in map
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
}
|
||||
}
|
||||
else if ( !ioNode )
|
||||
ev->NilPointerError();
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkNodeMap::CutNode(morkEnv* ev, mork_token inToken)
|
||||
{
|
||||
morkNode* node = 0; // old val in the map
|
||||
mork_bool outCutNode = this->Cut(ev, &inToken,
|
||||
/*key*/ (void*) 0, &node, (mork_change**) 0);
|
||||
if ( node )
|
||||
node->CutStrongRef(ev);
|
||||
|
||||
return outCutNode;
|
||||
}
|
||||
|
||||
morkNode*
|
||||
morkNodeMap::GetNode(morkEnv* ev, mork_token inToken)
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
{
|
||||
morkNode* node = 0; // old val in the map
|
||||
this->Get(ev, &inToken, /*key*/ (void*) 0, &node, (mork_change**) 0);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
mork_num
|
||||
morkNodeMap::CutAllNodes(morkEnv* ev)
|
||||
// CutAllNodes() releases all the reference node values.
|
||||
{
|
||||
mork_num outSlots = mMap_Slots;
|
||||
mork_token key = 0; // old key token in the map
|
||||
morkNode* val = 0; // old val node in the map
|
||||
|
||||
mork_change* c = 0;
|
||||
morkNodeMapIter i(ev, this);
|
||||
for ( c = i.FirstNode(ev, &key, &val); c ; c = i.NextNode(ev, &key, &val) )
|
||||
{
|
||||
if ( val )
|
||||
val->CutStrongRef(ev);
|
||||
i.CutHereNode(ev, /*key*/ (mork_token*) 0, /*val*/ (morkNode**) 0);
|
||||
}
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#define _MORKNODEMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKINTMAP_
|
||||
#include "morkIntMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kNodeMap /*i*/ 0x6E4D /* ascii 'nM' */
|
||||
|
||||
#define morkNodeMap_kStartSlotCount 512
|
||||
|
||||
/*| morkNodeMap: maps mork_token -> morkNode
|
||||
|*/
|
||||
class morkNodeMap : public morkIntMap { // for mapping tokens to nodes
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseNodeMap() only if open
|
||||
virtual ~morkNodeMap(); // assert that CloseNodeMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkNodeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseNodeMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsNodeMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kNodeMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
// use the Equal() and Hash() for mork_u4 inherited from morkIntMap
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
protected: // we want all subclasses to provide typesafe wrappers:
|
||||
|
||||
mork_bool AddNode(morkEnv* ev, mork_token inToken, morkNode* ioNode);
|
||||
// the AddNode() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutNode(morkEnv* ev, mork_token inToken);
|
||||
// The CutNode() boolean return indicates whether removal happened.
|
||||
|
||||
morkNode* GetNode(morkEnv* ev, mork_token inToken);
|
||||
// Note the returned node does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllNodes(morkEnv* ev);
|
||||
// CutAllNodes() releases all the reference node values.
|
||||
};
|
||||
|
||||
class morkNodeMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkNodeMapIter(morkEnv* ev, morkNodeMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkNodeMapIter( ) : morkMapIter() { }
|
||||
void InitNodeMapIter(morkEnv* ev, morkNodeMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change*
|
||||
FirstNode(morkEnv* ev, mork_token* outToken, morkNode** outNode)
|
||||
{ return this->First(ev, outToken, outNode); }
|
||||
|
||||
mork_change*
|
||||
NextNode(morkEnv* ev, mork_token* outToken, morkNode** outNode)
|
||||
{ return this->Next(ev, outToken, outNode); }
|
||||
|
||||
mork_change*
|
||||
HereNode(morkEnv* ev, mork_token* outToken, morkNode** outNode)
|
||||
{ return this->Here(ev, outToken, outNode); }
|
||||
|
||||
mork_change*
|
||||
CutHereNode(morkEnv* ev, mork_token* outToken, morkNode** outNode)
|
||||
{ return this->CutHere(ev, outToken, outNode); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKNODEMAP_ */
|
|
@ -0,0 +1,223 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKHANDLE_
|
||||
#include "morkHandle.h"
|
||||
#endif
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
NS_IMPL_ISUPPORTS1(morkObject, nsIMdbObject)
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkObject::CloseMorkNode(morkEnv* ev) // CloseObject() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseObject(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkObject::~morkObject() // assert CloseObject() executed earlier
|
||||
{
|
||||
if (!IsShutNode())
|
||||
CloseMorkNode(this->mMorkEnv);
|
||||
MORK_ASSERT(mObject_Handle==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkObject::morkObject(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor)
|
||||
: morkBead(inUsage, ioHeap, inBeadColor)
|
||||
, mObject_Handle( 0 )
|
||||
{
|
||||
mMorkEnv = nsnull;
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkObject::morkObject(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor, morkHandle* ioHandle)
|
||||
: morkBead(ev, inUsage, ioHeap, inBeadColor)
|
||||
, mObject_Handle( 0 )
|
||||
{
|
||||
mMorkEnv = ev;
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioHandle )
|
||||
morkHandle::SlotWeakHandle(ioHandle, ev, &mObject_Handle);
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kObject;
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkObject::CloseObject(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
if ( !this->IsShutNode() )
|
||||
{
|
||||
if ( mObject_Handle )
|
||||
morkHandle::SlotWeakHandle((morkHandle*) 0L, ev, &mObject_Handle);
|
||||
|
||||
mBead_Color = 0; // this->CloseBead(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
// { ----- begin factory methods -----
|
||||
NS_IMETHODIMP
|
||||
morkObject::GetMdbFactory(nsIMdbEnv* mev, nsIMdbFactory** acqFactory)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr <nsIMdbObject> obj = do_QueryInterface(mev);
|
||||
if (obj)
|
||||
rv = obj->GetMdbFactory(mev, acqFactory);
|
||||
else
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
return rv;
|
||||
}
|
||||
// } ----- end factory methods -----
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
NS_IMETHODIMP
|
||||
morkObject::GetWeakRefCount(nsIMdbEnv* mev, // weak refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
*outCount = WeakRefsOnly();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkObject::GetStrongRefCount(nsIMdbEnv* mev, // strong refs
|
||||
mdb_count* outCount)
|
||||
{
|
||||
*outCount = StrongRefsOnly();
|
||||
return NS_OK;
|
||||
}
|
||||
// ### TODO - clean up this cast, if required
|
||||
NS_IMETHODIMP
|
||||
morkObject::AddWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::AddWeakRef((morkEnv *) mev);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkObject::AddStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::AddStrongRef((morkEnv *) mev);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkObject::CutWeakRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CutWeakRef((morkEnv *) mev);
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkObject::CutStrongRef(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CutStrongRef((morkEnv *) mev);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkObject::CloseMdbObject(nsIMdbEnv* mev)
|
||||
{
|
||||
return morkNode::CloseMdbObject((morkEnv *) mev);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkObject::IsOpenMdbObject(nsIMdbEnv* mev, mdb_bool* outOpen)
|
||||
{
|
||||
*outOpen = IsOpenNode();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkObject::IsFrozenMdbObject(nsIMdbEnv* mev, mdb_bool* outIsReadonly)
|
||||
{
|
||||
*outIsReadonly = IsFrozen();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//void morkObject::NewNilHandleError(morkEnv* ev) // mObject_Handle is nil
|
||||
//{
|
||||
// ev->NewError("nil mObject_Handle");
|
||||
//}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#define _MORKOBJECT_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#include "morkBead.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCONFIG_
|
||||
#include "morkConfig.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINHEAP_
|
||||
#include "orkinHeap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kObject /*i*/ 0x6F42 /* ascii 'oB' */
|
||||
|
||||
/*| morkObject: subclass of morkNode that adds knowledge of db suite factory
|
||||
**| and containing port to those objects that are exposed as instances of
|
||||
**| nsIMdbObject in the public interface.
|
||||
|*/
|
||||
class morkObject : public morkBead, public nsIMdbObject {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
morkEnv * mMorkEnv; // weak ref to environment this object created in.
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseObject() only if open
|
||||
virtual ~morkObject(); // assert that CloseObject() executed earlier
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
void operator delete(void* ioAddress, size_t size)
|
||||
{
|
||||
mork_u4* array = (mork_u4*) ioAddress;
|
||||
array -= 3;
|
||||
orkinHeap *heap = (orkinHeap *) *array;
|
||||
if (heap)
|
||||
heap->Free(nsnull, ioAddress);
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly);
|
||||
// same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin factory methods -----
|
||||
NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory);
|
||||
// } ----- end factory methods -----
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev, // weak refs
|
||||
mdb_count* outCount);
|
||||
NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev, // strong refs
|
||||
mdb_count* outCount);
|
||||
|
||||
NS_IMETHOD AddWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD AddStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CutWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD CutStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); // called at strong refs zero
|
||||
NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen);
|
||||
// } ----- end ref counting -----
|
||||
|
||||
|
||||
protected: // special case construction of first env without preceding env
|
||||
morkObject(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor);
|
||||
|
||||
public: // morkEnv construction & destruction
|
||||
morkObject(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
mork_color inBeadColor, morkHandle* ioHandle); // ioHandle can be nil
|
||||
void CloseObject(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkObject(const morkObject& other);
|
||||
morkObject& operator=(const morkObject& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsObject() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kObject; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// void NewNilHandleError(morkEnv* ev); // mObject_Handle is nil
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakObject(morkObject* me,
|
||||
morkEnv* ev, morkObject** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongObject(morkObject* me,
|
||||
morkEnv* ev, morkObject** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKOBJECT_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,565 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKPARSER_
|
||||
#define _MORKPARSER_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSINK_
|
||||
#include "morkSink.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKYARN_
|
||||
#include "morkYarn.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*=============================================================================
|
||||
* morkPlace: stream byte position and stream line count
|
||||
*/
|
||||
|
||||
class morkPlace {
|
||||
public:
|
||||
mork_pos mPlace_Pos; // byte offset in an input stream
|
||||
mork_line mPlace_Line; // line count in an input stream
|
||||
|
||||
void ClearPlace()
|
||||
{
|
||||
mPlace_Pos = 0; mPlace_Line = 0;
|
||||
}
|
||||
|
||||
void SetPlace(mork_pos inPos, mork_line inLine)
|
||||
{
|
||||
mPlace_Pos = inPos; mPlace_Line = inLine;
|
||||
}
|
||||
|
||||
morkPlace() { mPlace_Pos = 0; mPlace_Line = 0; }
|
||||
|
||||
morkPlace(mork_pos inPos, mork_line inLine)
|
||||
{ mPlace_Pos = inPos; mPlace_Line = inLine; }
|
||||
|
||||
morkPlace(const morkPlace& inPlace)
|
||||
: mPlace_Pos(inPlace.mPlace_Pos), mPlace_Line(inPlace.mPlace_Line) { }
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkGlitch: stream place and error comment describing a parsing error
|
||||
*/
|
||||
|
||||
class morkGlitch {
|
||||
public:
|
||||
morkPlace mGlitch_Place; // place in stream where problem happened
|
||||
const char* mGlitch_Comment; // null-terminated ASCII C string
|
||||
|
||||
morkGlitch() { mGlitch_Comment = 0; }
|
||||
|
||||
morkGlitch(const morkPlace& inPlace, const char* inComment)
|
||||
: mGlitch_Place(inPlace), mGlitch_Comment(inComment) { }
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkMid: all possible ways needed to express an alias ID in Mork syntax
|
||||
*/
|
||||
|
||||
/*| morkMid: an abstraction of all the variations we might need to support
|
||||
**| in order to present an ID through the parser interface most cheaply and
|
||||
**| with minimum transformation away from the original text format.
|
||||
**|
|
||||
**|| An ID can have one of four forms:
|
||||
**| 1) idHex (mMid_Oid.mOid_Id <- idHex)
|
||||
**| 2) idHex:^scopeHex (mMid_Oid.mOid_Id <- idHex, mOid_Scope <- scopeHex)
|
||||
**| 3) idHex:scopeName (mMid_Oid.mOid_Id <- idHex, mMid_Buf <- scopeName)
|
||||
**| 4) columnName (mMid_Buf <- columnName, for columns in cells only)
|
||||
**|
|
||||
**|| Typically, mMid_Oid.mOid_Id will hold a nonzero integer value for
|
||||
**| an ID, but we might have an optional scope specified by either an integer
|
||||
**| in hex format, or a string name. (Note that while the first ID can be
|
||||
**| scoped variably, any integer ID for a scope is assumed always located in
|
||||
**| the same scope, so the second ID need not be disambiguated.)
|
||||
**|
|
||||
**|| The only time mMid_Oid.mOid_Id is ever zero is when mMid_Buf alone
|
||||
**| is nonzero, to indicate an explicit string instead of an alias appeared.
|
||||
**| This case happens to make the representation of columns in cells somewhat
|
||||
**| easier to represent, since columns can just appear as a string name; and
|
||||
**| this unifies those interfaces with row and table APIs expecting IDs.
|
||||
**|
|
||||
**|| So when the parser passes an instance of morkMid to a subclass, the
|
||||
**| mMid_Oid.mOid_Id slot should usually be nonzero. And the other two
|
||||
**| slots, mMid_Oid.mOid_Scope and mMid_Buf, might both be zero, or at
|
||||
**| most one of them will be nonzero to indicate an explicit scope; the
|
||||
**| parser is responsible for ensuring at most one of these is nonzero.
|
||||
|*/
|
||||
class morkMid {
|
||||
public:
|
||||
mdbOid mMid_Oid; // mOid_Scope is zero when not specified
|
||||
const morkBuf* mMid_Buf; // points to some specific buf subclass
|
||||
|
||||
morkMid()
|
||||
{ mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
|
||||
mMid_Buf = 0; }
|
||||
|
||||
void InitMidWithCoil(morkCoil* ioCoil)
|
||||
{ mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
|
||||
mMid_Buf = ioCoil; }
|
||||
|
||||
void ClearMid()
|
||||
{ mMid_Oid.mOid_Scope = 0; mMid_Oid.mOid_Id = morkId_kMinusOne;
|
||||
mMid_Buf = 0; }
|
||||
|
||||
morkMid(const morkMid& other)
|
||||
: mMid_Oid(other.mMid_Oid), mMid_Buf(other.mMid_Buf) { }
|
||||
|
||||
mork_bool HasNoId() const // ID is unspecified?
|
||||
{ return ( mMid_Oid.mOid_Id == morkId_kMinusOne ); }
|
||||
|
||||
mork_bool HasSomeId() const // ID is specified?
|
||||
{ return ( mMid_Oid.mOid_Id != morkId_kMinusOne ); }
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkSpan: start and end stream byte position and stream line count
|
||||
*/
|
||||
|
||||
class morkSpan {
|
||||
public:
|
||||
morkPlace mSpan_Start;
|
||||
morkPlace mSpan_End;
|
||||
|
||||
public: // methods
|
||||
|
||||
public: // inlines
|
||||
morkSpan() { } // use inline empty constructor for each place
|
||||
|
||||
morkPlace* AsPlace() { return &mSpan_Start; }
|
||||
const morkPlace* AsConstPlace() const { return &mSpan_Start; }
|
||||
|
||||
void SetSpan(mork_pos inFromPos, mork_line inFromLine,
|
||||
mork_pos inToPos, mork_line inToLine)
|
||||
{
|
||||
mSpan_Start.SetPlace(inFromPos, inFromLine);
|
||||
mSpan_End.SetPlace(inToPos,inToLine);
|
||||
}
|
||||
|
||||
// setting end, useful to terminate a span using current port span end:
|
||||
void SetEndWithEnd(const morkSpan& inSpan) // end <- span.end
|
||||
{ mSpan_End = inSpan.mSpan_End; }
|
||||
|
||||
// setting start, useful to initiate a span using current port span end:
|
||||
void SetStartWithEnd(const morkSpan& inSpan) // start <- span.end
|
||||
{ mSpan_Start = inSpan.mSpan_End; }
|
||||
|
||||
void ClearSpan()
|
||||
{
|
||||
mSpan_Start.mPlace_Pos = 0; mSpan_Start.mPlace_Line = 0;
|
||||
mSpan_End.mPlace_Pos = 0; mSpan_End.mPlace_Line = 0;
|
||||
}
|
||||
|
||||
morkSpan(mork_pos inFromPos, mork_line inFromLine,
|
||||
mork_pos inToPos, mork_line inToLine)
|
||||
: mSpan_Start(inFromPos, inFromLine), mSpan_End(inToPos, inToLine)
|
||||
{ /* empty implementation */ }
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
* morkParser: for parsing Mork text syntax
|
||||
*/
|
||||
|
||||
#define morkParser_kMinGranularity 512 /* parse at least half 0.5K at once */
|
||||
#define morkParser_kMaxGranularity (64 * 1024) /* parse at most 64 K at once */
|
||||
|
||||
#define morkDerived_kParser /*i*/ 0x5073 /* ascii 'Ps' */
|
||||
#define morkParser_kTag /*i*/ 0x70417253 /* ascii 'pArS' */
|
||||
|
||||
// These are states for the simple parsing virtual machine. Needless to say,
|
||||
// these must be distinct, and preferrably in a contiguous integer range.
|
||||
// Don't change these constants without looking at switch statements in code.
|
||||
#define morkParser_kCellState 0 /* cell is tightest scope */
|
||||
#define morkParser_kMetaState 1 /* meta is tightest scope */
|
||||
#define morkParser_kRowState 2 /* row is tightest scope */
|
||||
#define morkParser_kTableState 3 /* table is tightest scope */
|
||||
#define morkParser_kDictState 4 /* dict is tightest scope */
|
||||
#define morkParser_kPortState 5 /* port is tightest scope */
|
||||
|
||||
#define morkParser_kStartState 6 /* parsing has not yet begun */
|
||||
#define morkParser_kDoneState 7 /* parsing is complete */
|
||||
#define morkParser_kBrokenState 8 /* parsing is to broken to work */
|
||||
|
||||
class morkParser /*d*/ : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkParser members
|
||||
|
||||
nsIMdbHeap* mParser_Heap; // refcounted heap used for allocation
|
||||
morkStream* mParser_Stream; // refcounted input stream
|
||||
|
||||
mork_u4 mParser_Tag; // must equal morkParser_kTag
|
||||
mork_count mParser_MoreGranularity; // constructor inBytesPerParseSegment
|
||||
|
||||
mork_u4 mParser_State; // state where parser should resume
|
||||
|
||||
// after finding ends of group transactions, we can re-seek the start:
|
||||
mork_pos mParser_GroupContentStartPos; // start of this group
|
||||
|
||||
morkMid mParser_TableMid; // table mid if inside a table
|
||||
morkMid mParser_RowMid; // row mid if inside a row
|
||||
morkMid mParser_CellMid; // cell mid if inside a row
|
||||
mork_gid mParser_GroupId; // group ID if inside a group
|
||||
|
||||
mork_bool mParser_InPort; // called OnNewPort but not OnPortEnd?
|
||||
mork_bool mParser_InDict; // called OnNewDict but not OnDictEnd?
|
||||
mork_bool mParser_InCell; // called OnNewCell but not OnCellEnd?
|
||||
mork_bool mParser_InMeta; // called OnNewMeta but not OnMetaEnd?
|
||||
|
||||
mork_bool mParser_InPortRow; // called OnNewPortRow but not OnPortRowEnd?
|
||||
mork_bool mParser_InRow; // called OnNewRow but not OnNewRowEnd?
|
||||
mork_bool mParser_InTable; // called OnNewMeta but not OnMetaEnd?
|
||||
mork_bool mParser_InGroup; // called OnNewGroup but not OnGroupEnd?
|
||||
|
||||
mork_change mParser_AtomChange; // driven by mParser_Change
|
||||
mork_change mParser_CellChange; // driven by mParser_Change
|
||||
mork_change mParser_RowChange; // driven by mParser_Change
|
||||
mork_change mParser_TableChange; // driven by mParser_Change
|
||||
|
||||
mork_change mParser_Change; // driven by modifier in text
|
||||
mork_bool mParser_IsBroken; // has the parse become broken?
|
||||
mork_bool mParser_IsDone; // has the parse finished?
|
||||
mork_bool mParser_DoMore; // mParser_MoreGranularity not exhausted?
|
||||
|
||||
morkMid mParser_Mid; // current alias being parsed
|
||||
// note that mParser_Mid.mMid_Buf points at mParser_ScopeCoil below:
|
||||
|
||||
// blob coils allocated in mParser_Heap
|
||||
morkCoil mParser_ScopeCoil; // place to accumulate ID scope blobs
|
||||
morkCoil mParser_ValueCoil; // place to accumulate value blobs
|
||||
morkCoil mParser_ColumnCoil; // place to accumulate column blobs
|
||||
morkCoil mParser_StringCoil; // place to accumulate string blobs
|
||||
|
||||
morkSpool mParser_ScopeSpool; // writes to mParser_ScopeCoil
|
||||
morkSpool mParser_ValueSpool; // writes to mParser_ValueCoil
|
||||
morkSpool mParser_ColumnSpool; // writes to mParser_ColumnCoil
|
||||
morkSpool mParser_StringSpool; // writes to mParser_StringCoil
|
||||
|
||||
// yarns allocated in mParser_Heap
|
||||
morkYarn mParser_MidYarn; // place to receive from MidToYarn()
|
||||
|
||||
// span showing current ongoing file position status:
|
||||
morkSpan mParser_PortSpan; // span of current db port file
|
||||
|
||||
// various spans denoting nested subspaces inside the file's port span:
|
||||
morkSpan mParser_GroupSpan; // span of current transaction group
|
||||
morkSpan mParser_DictSpan;
|
||||
morkSpan mParser_AliasSpan;
|
||||
morkSpan mParser_MetaSpan;
|
||||
morkSpan mParser_TableSpan;
|
||||
morkSpan mParser_RowSpan;
|
||||
morkSpan mParser_CellSpan;
|
||||
morkSpan mParser_ColumnSpan;
|
||||
morkSpan mParser_SlotSpan;
|
||||
|
||||
private: // convenience inlines
|
||||
|
||||
mork_pos HerePos() const
|
||||
{ return mParser_PortSpan.mSpan_End.mPlace_Pos; }
|
||||
|
||||
void SetHerePos(mork_pos inPos)
|
||||
{ mParser_PortSpan.mSpan_End.mPlace_Pos = inPos; }
|
||||
|
||||
void CountLineBreak()
|
||||
{ ++mParser_PortSpan.mSpan_End.mPlace_Line; }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseParser() only if open
|
||||
virtual ~morkParser(); // assert that CloseParser() executed earlier
|
||||
|
||||
public: // morkYarn construction & destruction
|
||||
morkParser(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
morkStream* ioStream, // the readonly stream for input bytes
|
||||
mdb_count inBytesPerParseSegment, // target for ParseMore()
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
|
||||
void CloseParser(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkParser(const morkParser& other);
|
||||
morkParser& operator=(const morkParser& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsParser() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kParser; }
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // errors and warnings
|
||||
static void UnexpectedEofError(morkEnv* ev);
|
||||
static void EofInsteadOfHexError(morkEnv* ev);
|
||||
static void ExpectedEqualError(morkEnv* ev);
|
||||
static void ExpectedHexDigitError(morkEnv* ev, int c);
|
||||
static void NonParserTypeError(morkEnv* ev);
|
||||
static void UnexpectedByteInMetaWarning(morkEnv* ev);
|
||||
|
||||
public: // other type methods
|
||||
mork_bool GoodParserTag() const { return mParser_Tag == morkParser_kTag; }
|
||||
void NonGoodParserError(morkEnv* ev);
|
||||
void NonUsableParserError(morkEnv* ev);
|
||||
// call when IsNode() or GoodParserTag() is false
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // in virtual morkParser methods, data flow subclass to parser
|
||||
|
||||
virtual void MidToYarn(morkEnv* ev,
|
||||
const morkMid& inMid, // typically an alias to concat with strings
|
||||
mdbYarn* outYarn) = 0;
|
||||
// The parser might ask that some aliases be turned into yarns, so they
|
||||
// can be concatenated into longer blobs under some circumstances. This
|
||||
// is an alternative to using a long and complex callback for many parts
|
||||
// for a single cell value.
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // out virtual morkParser methods, data flow parser to subclass
|
||||
|
||||
// The virtual methods below will be called in a pattern corresponding
|
||||
// to the following grammar isomorphic to the Mork grammar. There should
|
||||
// be no exceptions, so subclasses can rely on seeing an appropriate "end"
|
||||
// method whenever some "new" method has been seen earlier. In the event
|
||||
// that some error occurs that causes content to be flushed, or sudden early
|
||||
// termination of a larger containing entity, we will always call a more
|
||||
// enclosed "end" method before we call an "end" method with greater scope.
|
||||
|
||||
// Note the "mp" prefix stands for "Mork Parser":
|
||||
|
||||
// mp:Start ::= OnNewPort mp:PortItem* OnPortEnd
|
||||
// mp:PortItem ::= mp:Content | mp:Group | OnPortGlitch
|
||||
// mp:Group ::= OnNewGroup mp:GroupItem* mp:GroupEnd
|
||||
// mp:GroupItem ::= mp:Content | OnGroupGlitch
|
||||
// mp:GroupEnd ::= OnGroupCommitEnd | OnGroupAbortEnd
|
||||
// mp:Content ::= mp:PortRow | mp:Dict | mp:Table | mp:Row
|
||||
// mp:PortRow ::= OnNewPortRow mp:RowItem* OnPortRowEnd
|
||||
// mp:Dict ::= OnNewDict mp:DictItem* OnDictEnd
|
||||
// mp:DictItem ::= OnAlias | OnAliasGlitch | mp:Meta | OnDictGlitch
|
||||
// mp:Table ::= OnNewTable mp:TableItem* OnTableEnd
|
||||
// mp:TableItem ::= mp:Row | mp:MetaTable | OnTableGlitch
|
||||
// mp:MetaTable ::= OnNewMeta mp:MetaItem* mp:Row OnMetaEnd
|
||||
// mp:Meta ::= OnNewMeta mp:MetaItem* OnMetaEnd
|
||||
// mp:MetaItem ::= mp:Cell | OnMetaGlitch
|
||||
// mp:Row ::= OnMinusRow? OnNewRow mp:RowItem* OnRowEnd
|
||||
// mp:RowItem ::= mp:Cell | mp:Meta | OnRowGlitch
|
||||
// mp:Cell ::= OnMinusCell? OnNewCell mp:CellItem? OnCellEnd
|
||||
// mp:CellItem ::= mp:Slot | OnCellForm | OnCellGlitch
|
||||
// mp:Slot ::= OnValue | OnValueMid | OnRowMid | OnTableMid
|
||||
|
||||
|
||||
// Note that in interfaces below, mork_change parameters kAdd and kNil
|
||||
// both mean about the same thing by default. Only kCut is interesting,
|
||||
// because this usually means to remove members instead of adding them.
|
||||
|
||||
virtual void OnNewPort(morkEnv* ev, const morkPlace& inPlace) = 0;
|
||||
virtual void OnPortGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnPortEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewGroup(morkEnv* ev, const morkPlace& inPlace, mork_gid inGid) = 0;
|
||||
virtual void OnGroupGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnGroupCommitEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
virtual void OnGroupAbortEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewPortRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_change inChange) = 0;
|
||||
virtual void OnPortRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnPortRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewTable(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_bool inCutAllRows) = 0;
|
||||
virtual void OnTableGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnTableEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewMeta(morkEnv* ev, const morkPlace& inPlace) = 0;
|
||||
virtual void OnMetaGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnMetaEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnMinusRow(morkEnv* ev) = 0;
|
||||
virtual void OnNewRow(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid& inMid, mork_bool inCutAllCols) = 0;
|
||||
virtual void OnRowPos(morkEnv* ev, mork_pos inRowPos) = 0;
|
||||
virtual void OnRowGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnRowEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnNewDict(morkEnv* ev, const morkPlace& inPlace) = 0;
|
||||
virtual void OnDictGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnDictEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnAlias(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid) = 0;
|
||||
|
||||
virtual void OnAliasGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
|
||||
virtual void OnMinusCell(morkEnv* ev) = 0;
|
||||
virtual void OnNewCell(morkEnv* ev, const morkPlace& inPlace,
|
||||
const morkMid* inMid, const morkBuf* inBuf) = 0;
|
||||
// Exactly one of inMid and inBuf is nil, and the other is non-nil.
|
||||
// When hex ID syntax is used for a column, then inMid is not nil, and
|
||||
// when a naked string names a column, then inBuf is not nil.
|
||||
|
||||
virtual void OnCellGlitch(morkEnv* ev, const morkGlitch& inGlitch) = 0;
|
||||
virtual void OnCellForm(morkEnv* ev, mork_cscode inCharsetFormat) = 0;
|
||||
virtual void OnCellEnd(morkEnv* ev, const morkSpan& inSpan) = 0;
|
||||
|
||||
virtual void OnValue(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkBuf& inBuf) = 0;
|
||||
|
||||
virtual void OnValueMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid) = 0;
|
||||
|
||||
virtual void OnRowMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid) = 0;
|
||||
|
||||
virtual void OnTableMid(morkEnv* ev, const morkSpan& inSpan,
|
||||
const morkMid& inMid) = 0;
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected parser helper methods
|
||||
|
||||
void ParseChunk(morkEnv* ev); // find parse continuation and resume
|
||||
|
||||
void StartParse(morkEnv* ev); // prepare for parsing
|
||||
void StopParse(morkEnv* ev); // terminate parsing & call needed methods
|
||||
|
||||
int NextChar(morkEnv* ev); // next non-white content
|
||||
|
||||
void OnCellState(morkEnv* ev);
|
||||
void OnMetaState(morkEnv* ev);
|
||||
void OnRowState(morkEnv* ev);
|
||||
void OnTableState(morkEnv* ev);
|
||||
void OnDictState(morkEnv* ev);
|
||||
void OnPortState(morkEnv* ev);
|
||||
void OnStartState(morkEnv* ev);
|
||||
|
||||
void ReadCell(morkEnv* ev);
|
||||
void ReadRow(morkEnv* ev, int c);
|
||||
void ReadRowPos(morkEnv* ev);
|
||||
void ReadTable(morkEnv* ev);
|
||||
void ReadTableMeta(morkEnv* ev);
|
||||
void ReadDict(morkEnv* ev);
|
||||
mork_bool ReadContent(morkEnv* ev, mork_bool inInsideGroup);
|
||||
void ReadGroup(morkEnv* ev);
|
||||
mork_bool ReadEndGroupId(morkEnv* ev);
|
||||
mork_bool ReadAt(morkEnv* ev, mork_bool inInsideGroup);
|
||||
mork_bool FindGroupEnd(morkEnv* ev);
|
||||
void ReadMeta(morkEnv* ev, int inEndMeta);
|
||||
void ReadAlias(morkEnv* ev);
|
||||
mork_id ReadHex(morkEnv* ev, int* outNextChar);
|
||||
morkBuf* ReadValue(morkEnv* ev);
|
||||
morkBuf* ReadName(morkEnv* ev, int c);
|
||||
mork_bool ReadMid(morkEnv* ev, morkMid* outMid);
|
||||
void ReadDictForm(morkEnv *ev);
|
||||
void ReadCellForm(morkEnv *ev, int c);
|
||||
|
||||
mork_bool MatchPattern(morkEnv* ev, const char* inPattern);
|
||||
|
||||
void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan);
|
||||
|
||||
|
||||
// void EndSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
// { MORK_USED_2(ev,ioSpan); }
|
||||
|
||||
// void EndSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
// { MORK_USED_2(ev,ioSpan); }
|
||||
|
||||
// void StartSpanOnLastByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
// { MORK_USED_2(ev,ioSpan); }
|
||||
|
||||
// void StartSpanOnThisByte(morkEnv* ev, morkSpan* ioSpan)
|
||||
// { MORK_USED_2(ev,ioSpan); }
|
||||
|
||||
int eat_line_break(morkEnv* ev, int inLast);
|
||||
int eat_line_continue(morkEnv* ev); // last char was '\\'
|
||||
int eat_comment(morkEnv* ev); // last char was '/'
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkParser methods
|
||||
|
||||
mdb_count ParseMore( // return count of bytes consumed now
|
||||
morkEnv* ev, // context
|
||||
mork_pos* outPos, // current byte pos in the stream afterwards
|
||||
mork_bool* outDone, // is parsing finished?
|
||||
mork_bool* outBroken // is parsing irreparably dead and broken?
|
||||
);
|
||||
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakParser(morkParser* me,
|
||||
morkEnv* ev, morkParser** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongParser(morkParser* me,
|
||||
morkEnv* ev, morkParser** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKPARSER_ */
|
||||
|
|
@ -0,0 +1,589 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#include "morkAtom.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKHANDLE_
|
||||
#include "morkHandle.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#include "morkZone.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkPool::CloseMorkNode(morkEnv* ev) // ClosePool() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->ClosePool(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkPool::~morkPool() // assert ClosePool() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkPool::morkPool(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbHeap* ioSlotHeap)
|
||||
: morkNode(inUsage, ioHeap)
|
||||
, mPool_Heap( ioSlotHeap )
|
||||
, mPool_UsedFramesCount( 0 )
|
||||
, mPool_FreeFramesCount( 0 )
|
||||
{
|
||||
// mPool_Heap is NOT refcounted
|
||||
MORK_ASSERT(ioSlotHeap);
|
||||
if ( ioSlotHeap )
|
||||
mNode_Derived = morkDerived_kPool;
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkPool::morkPool(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
, mPool_Heap( ioSlotHeap )
|
||||
, mPool_UsedFramesCount( 0 )
|
||||
, mPool_FreeFramesCount( 0 )
|
||||
{
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
// mPool_Heap is NOT refcounted:
|
||||
// nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mPool_Heap);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kPool;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkPool::ClosePool(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
//MORK_USED_1(ioZone);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
nsIMdbHeap* heap = mPool_Heap;
|
||||
nsIMdbEnv* mev = ev->AsMdbEnv();
|
||||
morkLink* aLink;
|
||||
morkDeque* d = &mPool_FreeHandleFrames;
|
||||
while ( (aLink = d->RemoveFirst()) != 0 )
|
||||
heap->Free(mev, aLink);
|
||||
|
||||
// if the pool's closed, get rid of the frames in use too.
|
||||
d = &mPool_UsedHandleFrames;
|
||||
while ( (aLink = d->RemoveFirst()) != 0 )
|
||||
heap->Free(mev, aLink);
|
||||
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
|
||||
// alloc and free individual instances of handles (inside hand frames):
|
||||
morkHandleFace*
|
||||
morkPool::NewHandle(morkEnv* ev, mork_size inSize, morkZone* ioZone)
|
||||
{
|
||||
void* newBlock = 0;
|
||||
if ( inSize <= sizeof(morkHandleFrame) )
|
||||
{
|
||||
morkLink* firstLink = mPool_FreeHandleFrames.RemoveFirst();
|
||||
if ( firstLink )
|
||||
{
|
||||
newBlock = firstLink;
|
||||
if ( mPool_FreeFramesCount )
|
||||
--mPool_FreeFramesCount;
|
||||
else
|
||||
ev->NewWarning("mPool_FreeFramesCount underflow");
|
||||
}
|
||||
else
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkHandleFrame),
|
||||
(void**) &newBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ev->NewWarning("inSize > sizeof(morkHandleFrame)");
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), inSize, (void**) &newBlock);
|
||||
}
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
return (morkHandleFace*) newBlock;
|
||||
}
|
||||
|
||||
void
|
||||
morkPool::ZapHandle(morkEnv* ev, morkHandleFace* ioHandle)
|
||||
{
|
||||
if ( ioHandle )
|
||||
{
|
||||
morkLink* handleLink = (morkLink*) ioHandle;
|
||||
mPool_FreeHandleFrames.AddLast(handleLink);
|
||||
++mPool_FreeFramesCount;
|
||||
// lets free all handles to track down leaks
|
||||
// - uncomment out next 3 lines, comment out above 2
|
||||
// nsIMdbHeap* heap = mPool_Heap;
|
||||
// nsIMdbEnv* mev = ev->AsMdbEnv();
|
||||
// heap->Free(mev, handleLink);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// alloc and free individual instances of rows:
|
||||
morkRow*
|
||||
morkPool::NewRow(morkEnv* ev, morkZone* ioZone) // allocate a new row instance
|
||||
{
|
||||
morkRow* newRow = 0;
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newRow = (morkRow*) ioZone->ZoneNewChip(ev, sizeof(morkRow));
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkRow), (void**) &newRow);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
if ( newRow )
|
||||
MORK_MEMSET(newRow, 0, sizeof(morkRow));
|
||||
|
||||
return newRow;
|
||||
}
|
||||
|
||||
void
|
||||
morkPool::ZapRow(morkEnv* ev, morkRow* ioRow,
|
||||
morkZone* ioZone) // free old row instance
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
if ( !ioRow )
|
||||
ev->NilPointerWarning(); // a zone 'chip' cannot be freed
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
if ( ioRow )
|
||||
mPool_Heap->Free(ev->AsMdbEnv(), ioRow);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
// alloc and free entire vectors of cells (not just one cell at a time)
|
||||
morkCell*
|
||||
morkPool::NewCells(morkEnv* ev, mork_size inSize,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
morkCell* newCells = 0;
|
||||
|
||||
mork_size size = inSize * sizeof(morkCell);
|
||||
if ( size )
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'run' knows its size, and can indeed be deallocated:
|
||||
newCells = (morkCell*) ioZone->ZoneNewRun(ev, size);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**) &newCells);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
// note morkAtom depends on having nil stored in all new mCell_Atom slots:
|
||||
if ( newCells )
|
||||
MORK_MEMSET(newCells, 0, size);
|
||||
return newCells;
|
||||
}
|
||||
|
||||
void
|
||||
morkPool::ZapCells(morkEnv* ev, morkCell* ioVector, mork_size inSize,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
MORK_USED_1(inSize);
|
||||
|
||||
if ( ioVector )
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'run' knows its size, and can indeed be deallocated:
|
||||
ioZone->ZoneZapRun(ev, ioVector);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Free(ev->AsMdbEnv(), ioVector);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
}
|
||||
|
||||
// resize (grow or trim) cell vectors inside a containing row instance
|
||||
mork_bool
|
||||
morkPool::AddRowCells(morkEnv* ev, morkRow* ioRow, mork_size inNewSize,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
// note strong implementation similarity to morkArray::Grow()
|
||||
|
||||
MORK_USED_1(ioZone);
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
mork_fill fill = ioRow->mRow_Length;
|
||||
if ( ev->Good() && fill < inNewSize ) // need more cells?
|
||||
{
|
||||
morkCell* newCells = this->NewCells(ev, inNewSize, ioZone);
|
||||
if ( newCells )
|
||||
{
|
||||
morkCell* c = newCells; // for iterating during copy
|
||||
morkCell* oldCells = ioRow->mRow_Cells;
|
||||
morkCell* end = oldCells + fill; // copy all the old cells
|
||||
while ( oldCells < end )
|
||||
{
|
||||
*c++ = *oldCells++; // bitwise copy each old cell struct
|
||||
}
|
||||
oldCells = ioRow->mRow_Cells;
|
||||
ioRow->mRow_Cells = newCells;
|
||||
ioRow->mRow_Length = (mork_u2) inNewSize;
|
||||
++ioRow->mRow_Seed;
|
||||
|
||||
if ( oldCells )
|
||||
this->ZapCells(ev, oldCells, fill, ioZone);
|
||||
}
|
||||
}
|
||||
return ( ev->Good() && ioRow->mRow_Length >= inNewSize );
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkPool::CutRowCells(morkEnv* ev, morkRow* ioRow,
|
||||
mork_size inNewSize,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
MORK_USED_1(ioZone);
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
mork_fill fill = ioRow->mRow_Length;
|
||||
if ( ev->Good() && fill > inNewSize ) // need fewer cells?
|
||||
{
|
||||
if ( inNewSize ) // want any row cells at all?
|
||||
{
|
||||
morkCell* newCells = this->NewCells(ev, inNewSize, ioZone);
|
||||
if ( newCells )
|
||||
{
|
||||
morkCell* saveNewCells = newCells; // Keep newcell pos
|
||||
morkCell* oldCells = ioRow->mRow_Cells;
|
||||
morkCell* oldEnd = oldCells + fill; // one past all old cells
|
||||
morkCell* newEnd = oldCells + inNewSize; // copy only kept old cells
|
||||
while ( oldCells < newEnd )
|
||||
{
|
||||
*newCells++ = *oldCells++; // bitwise copy each old cell struct
|
||||
}
|
||||
while ( oldCells < oldEnd )
|
||||
{
|
||||
if ( oldCells->mCell_Atom ) // need to unref old cell atom?
|
||||
oldCells->SetAtom(ev, (morkAtom*) 0, this); // unref cell atom
|
||||
++oldCells;
|
||||
}
|
||||
oldCells = ioRow->mRow_Cells;
|
||||
ioRow->mRow_Cells = saveNewCells;
|
||||
ioRow->mRow_Length = (mork_u2) inNewSize;
|
||||
++ioRow->mRow_Seed;
|
||||
|
||||
if ( oldCells )
|
||||
this->ZapCells(ev, oldCells, fill, ioZone);
|
||||
}
|
||||
}
|
||||
else // get rid of all row cells
|
||||
{
|
||||
morkCell* oldCells = ioRow->mRow_Cells;
|
||||
ioRow->mRow_Cells = 0;
|
||||
ioRow->mRow_Length = 0;
|
||||
++ioRow->mRow_Seed;
|
||||
|
||||
if ( oldCells )
|
||||
this->ZapCells(ev, oldCells, fill, ioZone);
|
||||
}
|
||||
}
|
||||
return ( ev->Good() && ioRow->mRow_Length <= inNewSize );
|
||||
}
|
||||
|
||||
// alloc & free individual instances of atoms (lots of atom subclasses):
|
||||
void
|
||||
morkPool::ZapAtom(morkEnv* ev, morkAtom* ioAtom,
|
||||
morkZone* ioZone) // any subclass (by kind)
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
if ( !ioAtom )
|
||||
ev->NilPointerWarning(); // a zone 'chip' cannot be freed
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
if ( ioAtom )
|
||||
mPool_Heap->Free(ev->AsMdbEnv(), ioAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
morkOidAtom*
|
||||
morkPool::NewRowOidAtom(morkEnv* ev, const mdbOid& inOid,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
morkOidAtom* newAtom = 0;
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkOidAtom*) ioZone->ZoneNewChip(ev, sizeof(morkOidAtom));
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkOidAtom),(void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
if ( newAtom )
|
||||
newAtom->InitRowOidAtom(ev, inOid);
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
morkOidAtom*
|
||||
morkPool::NewTableOidAtom(morkEnv* ev, const mdbOid& inOid,
|
||||
morkZone* ioZone)
|
||||
{
|
||||
morkOidAtom* newAtom = 0;
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkOidAtom*) ioZone->ZoneNewChip(ev, sizeof(morkOidAtom));
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkOidAtom), (void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
if ( newAtom )
|
||||
newAtom->InitTableOidAtom(ev, inOid);
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
morkAtom*
|
||||
morkPool::NewAnonAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm,
|
||||
morkZone* ioZone)
|
||||
// if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
|
||||
// anon atom will be created, and otherwise a 'big' anon atom.
|
||||
{
|
||||
morkAtom* newAtom = 0;
|
||||
|
||||
mork_bool needBig = ( inForm || inBuf.mBuf_Fill > 255 );
|
||||
mork_size size = ( needBig )?
|
||||
morkBigAnonAtom::SizeForFill(inBuf.mBuf_Fill) :
|
||||
morkWeeAnonAtom::SizeForFill(inBuf.mBuf_Fill);
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkAtom*) ioZone->ZoneNewChip(ev, size);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
if ( newAtom )
|
||||
{
|
||||
if ( needBig )
|
||||
((morkBigAnonAtom*) newAtom)->InitBigAnonAtom(ev, inBuf, inForm);
|
||||
else
|
||||
((morkWeeAnonAtom*) newAtom)->InitWeeAnonAtom(ev, inBuf);
|
||||
}
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkPool::NewBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid,
|
||||
morkZone* ioZone)
|
||||
// if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
|
||||
// book atom will be created, and otherwise a 'big' book atom.
|
||||
{
|
||||
morkBookAtom* newAtom = 0;
|
||||
|
||||
mork_bool needBig = ( inForm || inBuf.mBuf_Fill > 255 );
|
||||
mork_size size = ( needBig )?
|
||||
morkBigBookAtom::SizeForFill(inBuf.mBuf_Fill) :
|
||||
morkWeeBookAtom::SizeForFill(inBuf.mBuf_Fill);
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkBookAtom*) ioZone->ZoneNewChip(ev, size);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
if ( newAtom )
|
||||
{
|
||||
if ( needBig )
|
||||
((morkBigBookAtom*) newAtom)->InitBigBookAtom(ev,
|
||||
inBuf, inForm, ioSpace, inAid);
|
||||
else
|
||||
((morkWeeBookAtom*) newAtom)->InitWeeBookAtom(ev,
|
||||
inBuf, ioSpace, inAid);
|
||||
}
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkPool::NewBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom,
|
||||
morkZone* ioZone)
|
||||
// make the smallest kind of book atom that can hold content in inAtom.
|
||||
// The inAtom parameter is often expected to be a staged book atom in
|
||||
// the store, which was used to search an atom space for existing atoms.
|
||||
{
|
||||
morkBookAtom* newAtom = 0;
|
||||
|
||||
mork_cscode form = inAtom.mBigBookAtom_Form;
|
||||
mork_fill fill = inAtom.mBigBookAtom_Size;
|
||||
mork_bool needBig = ( form || fill > 255 );
|
||||
mork_size size = ( needBig )?
|
||||
morkBigBookAtom::SizeForFill(fill) :
|
||||
morkWeeBookAtom::SizeForFill(fill);
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkBookAtom*) ioZone->ZoneNewChip(ev, size);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
if ( newAtom )
|
||||
{
|
||||
morkBuf buf(inAtom.mBigBookAtom_Body, fill);
|
||||
if ( needBig )
|
||||
((morkBigBookAtom*) newAtom)->InitBigBookAtom(ev,
|
||||
buf, form, inAtom.mBookAtom_Space, inAtom.mBookAtom_Id);
|
||||
else
|
||||
((morkWeeBookAtom*) newAtom)->InitWeeBookAtom(ev,
|
||||
buf, inAtom.mBookAtom_Space, inAtom.mBookAtom_Id);
|
||||
}
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
morkBookAtom*
|
||||
morkPool::NewFarBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom,
|
||||
morkZone* ioZone)
|
||||
// make the smallest kind of book atom that can hold content in inAtom.
|
||||
// The inAtom parameter is often expected to be a staged book atom in
|
||||
// the store, which was used to search an atom space for existing atoms.
|
||||
{
|
||||
morkBookAtom* newAtom = 0;
|
||||
|
||||
mork_cscode form = inAtom.mFarBookAtom_Form;
|
||||
mork_fill fill = inAtom.mFarBookAtom_Size;
|
||||
mork_bool needBig = ( form || fill > 255 );
|
||||
mork_size size = ( needBig )?
|
||||
morkBigBookAtom::SizeForFill(fill) :
|
||||
morkWeeBookAtom::SizeForFill(fill);
|
||||
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
// a zone 'chip' remembers no size, and so cannot be deallocated:
|
||||
newAtom = (morkBookAtom*) ioZone->ZoneNewChip(ev, size);
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
MORK_USED_1(ioZone);
|
||||
mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**) &newAtom);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
if ( newAtom )
|
||||
{
|
||||
morkBuf buf(inAtom.mFarBookAtom_Body, fill);
|
||||
if ( needBig )
|
||||
((morkBigBookAtom*) newAtom)->InitBigBookAtom(ev,
|
||||
buf, form, inAtom.mBookAtom_Space, inAtom.mBookAtom_Id);
|
||||
else
|
||||
((morkWeeBookAtom*) newAtom)->InitWeeBookAtom(ev,
|
||||
buf, inAtom.mBookAtom_Space, inAtom.mBookAtom_Id);
|
||||
}
|
||||
return newAtom;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#define _MORKPOOL_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class morkHandle;
|
||||
class morkHandleFrame;
|
||||
class morkHandleFace; // just an opaque cookie type
|
||||
class morkBigBookAtom;
|
||||
class morkFarBookAtom;
|
||||
|
||||
#define morkDerived_kPool /*i*/ 0x706C /* ascii 'pl' */
|
||||
|
||||
/*| morkPool: a place to manage pools of non-node objects that are memory
|
||||
**| managed out of large chunks of space, so that per-object management
|
||||
**| space overhead has no signficant cost.
|
||||
|*/
|
||||
class morkPool : public morkNode {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
nsIMdbHeap* mPool_Heap; // NON-refcounted heap instance
|
||||
|
||||
morkDeque mPool_Blocks; // linked list of large blocks from heap
|
||||
|
||||
// These two lists contain instances of morkHandleFrame:
|
||||
morkDeque mPool_UsedHandleFrames; // handle frames currently being used
|
||||
morkDeque mPool_FreeHandleFrames; // handle frames currently in free list
|
||||
|
||||
mork_count mPool_UsedFramesCount; // length of mPool_UsedHandleFrames
|
||||
mork_count mPool_FreeFramesCount; // length of mPool_UsedHandleFrames
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // ClosePool() only if open
|
||||
virtual ~morkPool(); // assert that ClosePool() executed earlier
|
||||
|
||||
public: // morkPool construction & destruction
|
||||
morkPool(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
morkPool(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
void ClosePool(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkPool(const morkPool& other);
|
||||
morkPool& operator=(const morkPool& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsPool() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kPool; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
void NonPoolTypeError(morkEnv* ev);
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
void* operator new(size_t inSize) CPP_THROW_NEW
|
||||
{ return ::operator new(inSize); }
|
||||
|
||||
|
||||
public: // other pool methods
|
||||
|
||||
// alloc and free individual instances of handles (inside hand frames):
|
||||
morkHandleFace* NewHandle(morkEnv* ev, mork_size inSize, morkZone* ioZone);
|
||||
void ZapHandle(morkEnv* ev, morkHandleFace* ioHandle);
|
||||
|
||||
// alloc and free individual instances of rows:
|
||||
morkRow* NewRow(morkEnv* ev, morkZone* ioZone); // alloc new row instance
|
||||
void ZapRow(morkEnv* ev, morkRow* ioRow, morkZone* ioZone); // free old row instance
|
||||
|
||||
// alloc and free entire vectors of cells (not just one cell at a time)
|
||||
morkCell* NewCells(morkEnv* ev, mork_size inSize, morkZone* ioZone);
|
||||
void ZapCells(morkEnv* ev, morkCell* ioVector, mork_size inSize, morkZone* ioZone);
|
||||
|
||||
// resize (grow or trim) cell vectors inside a containing row instance
|
||||
mork_bool AddRowCells(morkEnv* ev, morkRow* ioRow, mork_size inNewSize, morkZone* ioZone);
|
||||
mork_bool CutRowCells(morkEnv* ev, morkRow* ioRow, mork_size inNewSize, morkZone* ioZone);
|
||||
|
||||
// alloc & free individual instances of atoms (lots of atom subclasses):
|
||||
void ZapAtom(morkEnv* ev, morkAtom* ioAtom, morkZone* ioZone); // any subclass (by kind)
|
||||
|
||||
morkOidAtom* NewRowOidAtom(morkEnv* ev, const mdbOid& inOid, morkZone* ioZone);
|
||||
morkOidAtom* NewTableOidAtom(morkEnv* ev, const mdbOid& inOid, morkZone* ioZone);
|
||||
|
||||
morkAtom* NewAnonAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkZone* ioZone);
|
||||
// if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
|
||||
// anon atom will be created, and otherwise a 'big' anon atom.
|
||||
|
||||
morkBookAtom* NewBookAtom(morkEnv* ev, const morkBuf& inBuf,
|
||||
mork_cscode inForm, morkAtomSpace* ioSpace, mork_aid inAid, morkZone* ioZone);
|
||||
// if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
|
||||
// book atom will be created, and otherwise a 'big' book atom.
|
||||
|
||||
morkBookAtom* NewBookAtomCopy(morkEnv* ev, const morkBigBookAtom& inAtom, morkZone* ioZone);
|
||||
// make the smallest kind of book atom that can hold content in inAtom.
|
||||
// The inAtom parameter is often expected to be a staged book atom in
|
||||
// the store, which was used to search an atom space for existing atoms.
|
||||
|
||||
morkBookAtom* NewFarBookAtomCopy(morkEnv* ev, const morkFarBookAtom& inAtom, morkZone* ioZone);
|
||||
// make the smallest kind of book atom that can hold content in inAtom.
|
||||
// The inAtom parameter is often expected to be a staged book atom in
|
||||
// the store, which was used to search an atom space for existing atoms.
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakPool(morkPool* me,
|
||||
morkEnv* ev, morkPool** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongPool(morkPool* me,
|
||||
morkEnv* ev, morkPool** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKPOOL_ */
|
||||
|
|
@ -0,0 +1,468 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPORTTABLECURSOR_
|
||||
#include "morkPortTableCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkPortTableCursor::CloseMorkNode(morkEnv* ev) // ClosePortTableCursor() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->ClosePortTableCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkPortTableCursor::~morkPortTableCursor() // ClosePortTableCursor() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkPortTableCursor::morkPortTableCursor(morkEnv* ev,
|
||||
const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind, nsIMdbHeap* ioSlotHeap)
|
||||
: morkCursor(ev, inUsage, ioHeap)
|
||||
, mPortTableCursor_Store( 0 )
|
||||
, mPortTableCursor_RowScope( (mdb_scope) -1 ) // we want != inRowScope
|
||||
, mPortTableCursor_TableKind( (mdb_kind) -1 ) // we want != inTableKind
|
||||
, mPortTableCursor_LastTable ( 0 ) // not refcounted
|
||||
, mPortTableCursor_RowSpace( 0 ) // strong ref to row space
|
||||
, mPortTableCursor_TablesDidEnd( morkBool_kFalse )
|
||||
, mPortTableCursor_SpacesDidEnd( morkBool_kFalse )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
mCursor_Seed = 0; // let the iterator do its own seed handling
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mPortTableCursor_Store);
|
||||
|
||||
if ( this->SetRowScope(ev, inRowScope) )
|
||||
this->SetTableKind(ev, inTableKind);
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kPortTableCursor;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkPortTableCursor, morkCursor, nsIMdbPortTableCursor)
|
||||
|
||||
morkEnv*
|
||||
morkPortTableCursor::CanUsePortTableCursor(nsIMdbEnv* mev,
|
||||
mork_bool inMutable, mdb_err* outErr) const
|
||||
{
|
||||
morkEnv* outEnv = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( IsPortTableCursor() )
|
||||
outEnv = ev;
|
||||
else
|
||||
NonPortTableCursorTypeError(ev);
|
||||
*outErr = ev->AsErr();
|
||||
}
|
||||
MORK_ASSERT(outEnv);
|
||||
return outEnv;
|
||||
}
|
||||
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkPortTableCursor::ClosePortTableCursor(morkEnv* ev)
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
mCursor_Seed = 0;
|
||||
mPortTableCursor_LastTable = 0;
|
||||
morkStore::SlotWeakStore((morkStore*) 0, ev, &mPortTableCursor_Store);
|
||||
morkRowSpace::SlotStrongRowSpace((morkRowSpace*) 0, ev,
|
||||
&mPortTableCursor_RowSpace);
|
||||
this->CloseCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkPortTableCursor::NilCursorStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mPortTableCursor_Store");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkPortTableCursor::NonPortTableCursorTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkPortTableCursor");
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkPortTableCursor::SetRowScope(morkEnv* ev, mork_scope inRowScope)
|
||||
{
|
||||
mPortTableCursor_RowScope = inRowScope;
|
||||
mPortTableCursor_LastTable = 0; // restart iteration of space
|
||||
|
||||
mPortTableCursor_TableIter.CloseMapIter(ev);
|
||||
mPortTableCursor_TablesDidEnd = morkBool_kTrue;
|
||||
mPortTableCursor_SpacesDidEnd = morkBool_kTrue;
|
||||
|
||||
morkStore* store = mPortTableCursor_Store;
|
||||
if ( store )
|
||||
{
|
||||
morkRowSpace* space = mPortTableCursor_RowSpace;
|
||||
|
||||
if ( inRowScope ) // intend to cover a specific scope only?
|
||||
{
|
||||
space = store->LazyGetRowSpace(ev, inRowScope);
|
||||
morkRowSpace::SlotStrongRowSpace(space, ev,
|
||||
&mPortTableCursor_RowSpace);
|
||||
|
||||
// We want mPortTableCursor_SpacesDidEnd == morkBool_kTrue
|
||||
// to show this is the only space to be covered.
|
||||
}
|
||||
else // prepare space map iter to cover all space scopes
|
||||
{
|
||||
morkRowSpaceMapIter* rsi = &mPortTableCursor_SpaceIter;
|
||||
rsi->InitRowSpaceMapIter(ev, &store->mStore_RowSpaces);
|
||||
|
||||
space = 0;
|
||||
(void) rsi->FirstRowSpace(ev, (mork_scope*) 0, &space);
|
||||
morkRowSpace::SlotStrongRowSpace(space, ev,
|
||||
&mPortTableCursor_RowSpace);
|
||||
|
||||
if ( space ) // found first space in store
|
||||
mPortTableCursor_SpacesDidEnd = morkBool_kFalse;
|
||||
}
|
||||
|
||||
this->init_space_tables_map(ev);
|
||||
}
|
||||
else
|
||||
this->NilCursorStoreError(ev);
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
void
|
||||
morkPortTableCursor::init_space_tables_map(morkEnv* ev)
|
||||
{
|
||||
morkRowSpace* space = mPortTableCursor_RowSpace;
|
||||
if ( space && ev->Good() )
|
||||
{
|
||||
morkTableMapIter* ti = &mPortTableCursor_TableIter;
|
||||
ti->InitTableMapIter(ev, &space->mRowSpace_Tables);
|
||||
if ( ev->Good() )
|
||||
mPortTableCursor_TablesDidEnd = morkBool_kFalse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mork_bool
|
||||
morkPortTableCursor::SetTableKind(morkEnv* ev, mork_kind inTableKind)
|
||||
{
|
||||
mPortTableCursor_TableKind = inTableKind;
|
||||
mPortTableCursor_LastTable = 0; // restart iteration of space
|
||||
|
||||
mPortTableCursor_TablesDidEnd = morkBool_kTrue;
|
||||
|
||||
morkRowSpace* space = mPortTableCursor_RowSpace;
|
||||
if ( !space && mPortTableCursor_RowScope == 0 )
|
||||
{
|
||||
this->SetRowScope(ev, 0);
|
||||
space = mPortTableCursor_RowSpace;
|
||||
}
|
||||
this->init_space_tables_map(ev);
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkRowSpace*
|
||||
morkPortTableCursor::NextSpace(morkEnv* ev)
|
||||
{
|
||||
morkRowSpace* outSpace = 0;
|
||||
mPortTableCursor_LastTable = 0;
|
||||
mPortTableCursor_SpacesDidEnd = morkBool_kTrue;
|
||||
mPortTableCursor_TablesDidEnd = morkBool_kTrue;
|
||||
|
||||
if ( !mPortTableCursor_RowScope ) // not just one scope?
|
||||
{
|
||||
morkStore* store = mPortTableCursor_Store;
|
||||
if ( store )
|
||||
{
|
||||
morkRowSpaceMapIter* rsi = &mPortTableCursor_SpaceIter;
|
||||
|
||||
(void) rsi->NextRowSpace(ev, (mork_scope*) 0, &outSpace);
|
||||
morkRowSpace::SlotStrongRowSpace(outSpace, ev,
|
||||
&mPortTableCursor_RowSpace);
|
||||
|
||||
if ( outSpace ) // found next space in store
|
||||
{
|
||||
mPortTableCursor_SpacesDidEnd = morkBool_kFalse;
|
||||
|
||||
this->init_space_tables_map(ev);
|
||||
|
||||
if ( ev->Bad() )
|
||||
outSpace = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilCursorStoreError(ev);
|
||||
}
|
||||
|
||||
return outSpace;
|
||||
}
|
||||
|
||||
morkTable *
|
||||
morkPortTableCursor::NextTable(morkEnv* ev)
|
||||
{
|
||||
mork_kind kind = mPortTableCursor_TableKind;
|
||||
|
||||
do // until spaces end, or until we find a table in a space
|
||||
{
|
||||
morkRowSpace* space = mPortTableCursor_RowSpace;
|
||||
if ( mPortTableCursor_TablesDidEnd ) // current space exhausted?
|
||||
space = this->NextSpace(ev); // go on to the next space
|
||||
|
||||
if ( space ) // have a space remaining that might hold tables?
|
||||
{
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
morkTableMapIter* ti = &mPortTableCursor_TableIter;
|
||||
morkTable* table = ( mPortTableCursor_LastTable )?
|
||||
ti->NextTable(ev) : ti->FirstTable(ev);
|
||||
|
||||
for ( ; table && ev->Good(); table = ti->NextTable(ev) )
|
||||
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
mork_tid* key = 0; // ignore keys in table map
|
||||
morkTable* table = 0; // old value table in the map
|
||||
morkTableMapIter* ti = &mPortTableCursor_TableIter;
|
||||
mork_change* c = ( mPortTableCursor_LastTable )?
|
||||
ti->NextTable(ev, key, &table) : ti->FirstTable(ev, key, &table);
|
||||
|
||||
for ( ; c && ev->Good(); c = ti->NextTable(ev, key, &table) )
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
{
|
||||
if ( table && table->IsTable() )
|
||||
{
|
||||
if ( !kind || kind == table->mTable_Kind )
|
||||
{
|
||||
mPortTableCursor_LastTable = table; // ti->NextTable() hence
|
||||
return table;
|
||||
}
|
||||
}
|
||||
else
|
||||
table->NonTableTypeWarning(ev);
|
||||
}
|
||||
mPortTableCursor_TablesDidEnd = morkBool_kTrue; // space is done
|
||||
mPortTableCursor_LastTable = 0; // make sure next space starts fresh
|
||||
}
|
||||
|
||||
} while ( ev->Good() && !mPortTableCursor_SpacesDidEnd );
|
||||
|
||||
return (morkTable*) 0;
|
||||
}
|
||||
|
||||
|
||||
// { ----- begin table iteration methods -----
|
||||
|
||||
// { ===== begin nsIMdbPortTableCursor methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::SetPort(nsIMdbEnv* mev, nsIMdbPort* ioPort)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE,"not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::GetPort(nsIMdbEnv* mev, nsIMdbPort** acqPort)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbPort* outPort = 0;
|
||||
morkEnv* ev =
|
||||
this->CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mPortTableCursor_Store )
|
||||
outPort = mPortTableCursor_Store->AcquireStoreHandle(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqPort )
|
||||
*acqPort = outPort;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::SetRowScope(nsIMdbEnv* mev, // sets pos to -1
|
||||
mdb_scope inRowScope)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev =
|
||||
this->CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
|
||||
SetRowScope(ev, inRowScope);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::GetRowScope(nsIMdbEnv* mev, mdb_scope* outRowScope)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_scope rowScope = 0;
|
||||
morkEnv* ev =
|
||||
this->CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
rowScope = mPortTableCursor_RowScope;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
*outRowScope = rowScope;
|
||||
return outErr;
|
||||
}
|
||||
// setting row scope to zero iterates over all row scopes in port
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::SetTableKind(nsIMdbEnv* mev, // sets pos to -1
|
||||
mdb_kind inTableKind)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev =
|
||||
this->CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
|
||||
SetTableKind(ev, inTableKind);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::GetTableKind(nsIMdbEnv* mev, mdb_kind* outTableKind)
|
||||
// setting table kind to zero iterates over all table kinds in row scope
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_kind tableKind = 0;
|
||||
morkEnv* ev =
|
||||
this->CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
tableKind = mPortTableCursor_TableKind;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
*outTableKind = tableKind;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin table iteration methods -----
|
||||
NS_IMETHODIMP
|
||||
morkPortTableCursor::NextTable( // get table at next position in the db
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbTable** acqTable)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbTable* outTable = 0;
|
||||
morkEnv* ev =
|
||||
CanUsePortTableCursor(mev, /*inMutable*/ morkBool_kFalse, &outErr);
|
||||
if ( ev )
|
||||
{
|
||||
morkTable* table = NextTable(ev);
|
||||
if ( table && ev->Good() )
|
||||
outTable = table->AcquireTableHandle(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqTable )
|
||||
*acqTable = outTable;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,173 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKPORTTABLECURSOR_
|
||||
#define _MORKPORTTABLECURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#include "morkRowSpace.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class orkinPortTableCursor;
|
||||
#define morkDerived_kPortTableCursor /*i*/ 0x7443 /* ascii 'tC' */
|
||||
|
||||
class morkPortTableCursor : public morkCursor, public nsIMdbPortTableCursor { // row iterator
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkFactory* mObject_Factory; // weak ref to suite factory
|
||||
|
||||
// mork_seed mCursor_Seed;
|
||||
// mork_pos mCursor_Pos;
|
||||
// mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
// mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD SetPort(nsIMdbEnv* ev, nsIMdbPort* ioPort); // sets pos to -1
|
||||
NS_IMETHOD GetPort(nsIMdbEnv* ev, nsIMdbPort** acqPort);
|
||||
|
||||
NS_IMETHOD SetRowScope(nsIMdbEnv* ev, // sets pos to -1
|
||||
mdb_scope inRowScope);
|
||||
NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope);
|
||||
// setting row scope to zero iterates over all row scopes in port
|
||||
|
||||
NS_IMETHOD SetTableKind(nsIMdbEnv* ev, // sets pos to -1
|
||||
mdb_kind inTableKind);
|
||||
NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind);
|
||||
// setting table kind to zero iterates over all table kinds in row scope
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin table iteration methods -----
|
||||
NS_IMETHOD NextTable( // get table at next position in the db
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbTable** acqTable); // the next table in the iteration
|
||||
// } ----- end table iteration methods -----
|
||||
morkStore* mPortTableCursor_Store; // weak ref to store
|
||||
|
||||
mdb_scope mPortTableCursor_RowScope;
|
||||
mdb_kind mPortTableCursor_TableKind;
|
||||
|
||||
// We only care if LastTable is non-nil, so it is not refcounted;
|
||||
// so you must never access table state or methods using LastTable:
|
||||
|
||||
morkTable* mPortTableCursor_LastTable; // nil or last table (no refcount)
|
||||
morkRowSpace* mPortTableCursor_RowSpace; // current space (strong ref)
|
||||
|
||||
morkRowSpaceMapIter mPortTableCursor_SpaceIter; // iter over spaces
|
||||
morkTableMapIter mPortTableCursor_TableIter; // iter over tables
|
||||
|
||||
// these booleans indicate when the table or space iterator is exhausted:
|
||||
|
||||
mork_bool mPortTableCursor_TablesDidEnd; // no more tables?
|
||||
mork_bool mPortTableCursor_SpacesDidEnd; // no more spaces?
|
||||
mork_u1 mPortTableCursor_Pad[ 2 ]; // for u4 alignment
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // ClosePortTableCursor()
|
||||
virtual ~morkPortTableCursor(); // assert that close executed earlier
|
||||
|
||||
public: // morkPortTableCursor construction & destruction
|
||||
morkPortTableCursor(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind, nsIMdbHeap* ioSlotHeap);
|
||||
void ClosePortTableCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkPortTableCursor(const morkPortTableCursor& other);
|
||||
morkPortTableCursor& operator=(const morkPortTableCursor& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsPortTableCursor() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kPortTableCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
protected: // utilities
|
||||
|
||||
void init_space_tables_map(morkEnv* ev);
|
||||
|
||||
public: // other cursor methods
|
||||
|
||||
static void NilCursorStoreError(morkEnv* ev);
|
||||
static void NonPortTableCursorTypeError(morkEnv* ev);
|
||||
|
||||
morkEnv* CanUsePortTableCursor(nsIMdbEnv* mev,
|
||||
mork_bool inMutable, mdb_err* outErr) const;
|
||||
|
||||
|
||||
morkRowSpace* NextSpace(morkEnv* ev);
|
||||
morkTable* NextTable(morkEnv* ev);
|
||||
|
||||
mork_bool SetRowScope(morkEnv* ev, mork_scope inRowScope);
|
||||
mork_bool SetTableKind(morkEnv* ev, mork_kind inTableKind);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakPortTableCursor(morkPortTableCursor* me,
|
||||
morkEnv* ev, morkPortTableCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongPortTableCursor(morkPortTableCursor* me,
|
||||
morkEnv* ev, morkPortTableCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKPORTTABLECURSOR_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,431 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// This code is a port to NS Mork from public domain Mithril C++ sources.
|
||||
// Note many code comments here come verbatim from cut-and-pasted Mithril.
|
||||
// In many places, code is identical; Mithril versions stay public domain.
|
||||
// Changes in porting are mainly class type and scalar type name changes.
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#define _MORKPROBEMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class morkMapScratch { // utility class used by map subclasses
|
||||
public:
|
||||
nsIMdbHeap* sMapScratch_Heap; // cached sMap_Heap
|
||||
mork_count sMapScratch_Slots; // cached sMap_Slots
|
||||
|
||||
mork_u1* sMapScratch_Keys; // cached sMap_Keys
|
||||
mork_u1* sMapScratch_Vals; // cached sMap_Vals
|
||||
|
||||
public:
|
||||
void halt_map_scratch(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kProbeMap 0x7072 /* ascii 'pr' */
|
||||
#define morkProbeMap_kTag 0x70724D50 /* ascii 'prMP' */
|
||||
|
||||
#define morkProbeMap_kLazyClearOnAdd ((mork_u1) 'c')
|
||||
|
||||
class morkProbeMap: public morkNode {
|
||||
|
||||
protected:
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
protected:
|
||||
// { begin morkMap slots
|
||||
nsIMdbHeap* sMap_Heap; // strong ref to heap allocating all space
|
||||
|
||||
mork_u1* sMap_Keys;
|
||||
mork_u1* sMap_Vals;
|
||||
|
||||
mork_count sMap_Seed; // change count of members or structure
|
||||
|
||||
mork_count sMap_Slots; // count of slots in the hash table
|
||||
mork_fill sMap_Fill; // number of used slots in the hash table
|
||||
|
||||
mork_size sMap_KeySize; // size of each key (cannot be zero)
|
||||
mork_size sMap_ValSize; // size of each val (zero allowed)
|
||||
|
||||
mork_bool sMap_KeyIsIP; // sMap_KeySize == sizeof(mork_ip)
|
||||
mork_bool sMap_ValIsIP; // sMap_ValSize == sizeof(mork_ip)
|
||||
mork_u1 sMap_Pad[ 2 ]; // for u4 alignment
|
||||
// } end morkMap slots
|
||||
|
||||
friend class morkProbeMapIter; // for access to protected slots
|
||||
|
||||
public: // getters
|
||||
mork_count MapSeed() const { return sMap_Seed; }
|
||||
|
||||
mork_count MapSlots() const { return sMap_Slots; }
|
||||
mork_fill MapFill() const { return sMap_Fill; }
|
||||
|
||||
mork_size MapKeySize() const { return sMap_KeySize; }
|
||||
mork_size MapValSize() const { return sMap_ValSize; }
|
||||
|
||||
mork_bool MapKeyIsIP() const { return sMap_KeyIsIP; }
|
||||
mork_bool MapValIsIP() const { return sMap_ValIsIP; }
|
||||
|
||||
protected: // slots
|
||||
// { begin morkProbeMap slots
|
||||
|
||||
mork_fill sProbeMap_MaxFill; // max sMap_Fill before map must grow
|
||||
|
||||
mork_u1 sProbeMap_LazyClearOnAdd; // true if kLazyClearOnAdd
|
||||
mork_bool sProbeMap_ZeroIsClearKey; // zero is adequate to clear keys
|
||||
mork_u1 sProbeMap_Pad[ 2 ]; // for u4 alignment
|
||||
|
||||
mork_u4 sProbeMap_Tag;
|
||||
|
||||
// } end morkProbeMap slots
|
||||
|
||||
public: // lazy clear on add
|
||||
|
||||
mork_bool need_lazy_init() const
|
||||
{ return sProbeMap_LazyClearOnAdd == morkProbeMap_kLazyClearOnAdd; }
|
||||
|
||||
public: // typing
|
||||
mork_bool GoodProbeMap() const
|
||||
{ return sProbeMap_Tag == morkProbeMap_kTag; }
|
||||
|
||||
protected: // utilities
|
||||
|
||||
void* clear_alloc(morkEnv* ev, mork_size inSize);
|
||||
|
||||
mork_u1* map_new_vals(morkEnv* ev, mork_num inSlots);
|
||||
mork_u1* map_new_keys(morkEnv* ev, mork_num inSlots);
|
||||
|
||||
void clear_probe_map(morkEnv* ev, nsIMdbHeap* ioMapHeap);
|
||||
void init_probe_map(morkEnv* ev, mork_size inSlots);
|
||||
void probe_map_lazy_init(morkEnv* ev);
|
||||
|
||||
mork_bool new_slots(morkEnv* ev, morkMapScratch* old, mork_num inSlots);
|
||||
|
||||
mork_test find_key_pos(morkEnv* ev, const void* inAppKey,
|
||||
mork_u4 inHash, mork_pos* outPos) const;
|
||||
|
||||
void put_probe_kv(morkEnv* ev,
|
||||
const void* inAppKey, const void* inAppVal, mork_pos inPos);
|
||||
void get_probe_kv(morkEnv* ev,
|
||||
void* outAppKey, void* outAppVal, mork_pos inPos) const;
|
||||
|
||||
mork_bool grow_probe_map(morkEnv* ev);
|
||||
void rehash_old_map(morkEnv* ev, morkMapScratch* ioScratch);
|
||||
void revert_map(morkEnv* ev, morkMapScratch* ioScratch);
|
||||
|
||||
public: // errors
|
||||
void ProbeMapBadTagError(morkEnv* ev) const;
|
||||
void WrapWithNoVoidSlotError(morkEnv* ev) const;
|
||||
void GrowFailsMaxFillError(morkEnv* ev) const;
|
||||
void MapKeyIsNotIPError(morkEnv* ev) const;
|
||||
void MapValIsNotIPError(morkEnv* ev) const;
|
||||
|
||||
void MapNilKeysError(morkEnv* ev);
|
||||
void MapZeroKeySizeError(morkEnv* ev);
|
||||
|
||||
void MapSeedOutOfSyncError(morkEnv* ev);
|
||||
void MapFillUnderflowWarning(morkEnv* ev);
|
||||
|
||||
static void ProbeMapCutError(morkEnv* ev);
|
||||
|
||||
// { ===== begin morkMap methods =====
|
||||
public:
|
||||
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
// Note inMapKey is always a key already stored in the map, while inAppKey
|
||||
// is always a method argument parameter from a client method call.
|
||||
// This matters the most in morkProbeMap subclasses, which have the
|
||||
// responsibility of putting 'app' keys into slots for 'map' keys, and
|
||||
// the bit pattern representation might be different in such cases.
|
||||
// morkTest_kHit means that inMapKey equals inAppKey (and this had better
|
||||
// also imply that hash(inMapKey) == hash(inAppKey)).
|
||||
// morkTest_kMiss means that inMapKey does NOT equal inAppKey (but this
|
||||
// implies nothing at all about hash(inMapKey) and hash(inAppKey)).
|
||||
// morkTest_kVoid means that inMapKey is not a valid key bit pattern,
|
||||
// which means that key slot in the map is not being used. Note that
|
||||
// kVoid is only expected as a return value in morkProbeMap subclasses,
|
||||
// because morkProbeMap must ask whether a key slot is used or not.
|
||||
// morkChainMap however, always knows when a key slot is used, so only
|
||||
// key slots expected to have valid bit patterns will be presented to
|
||||
// the MapTest() methods for morkChainMap subclasses.
|
||||
//
|
||||
// NOTE: it is very important that subclasses correctly return the value
|
||||
// morkTest_kVoid whenever the slot for inMapKey contains a bit pattern
|
||||
// that means the slot is not being used, because this is the only way a
|
||||
// probe map can terminate an unsuccessful search for a key in the map.
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_bool
|
||||
MapAtPut(morkEnv* ev, const void* inAppKey, const void* inAppVal,
|
||||
void* outAppKey, void* outAppVal);
|
||||
|
||||
virtual mork_bool
|
||||
MapAt(morkEnv* ev, const void* inAppKey, void* outAppKey, void* outAppVal);
|
||||
|
||||
virtual mork_num
|
||||
MapCutAll(morkEnv* ev);
|
||||
// } ===== end morkMap methods =====
|
||||
|
||||
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
public:
|
||||
|
||||
virtual mork_u4
|
||||
ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
// ProbeMapHashMapKey() does logically the same thing as MapHash(), and
|
||||
// the default implementation actually calls virtual MapHash(). However,
|
||||
// Subclasses must override this method whenever the formats of keys in
|
||||
// the map differ from app keys outside the map, because MapHash() only
|
||||
// works on keys in 'app' format, while ProbeMapHashMapKey() only works
|
||||
// on keys in 'map' format. This method is called in order to rehash all
|
||||
// map keys when a map is grown, and this causes all old map members to
|
||||
// move into new slot locations.
|
||||
//
|
||||
// Note it is absolutely imperative that a hash for a key in 'map' format
|
||||
// be exactly the same the hash of the same key in 'app' format, or else
|
||||
// maps will seem corrupt later when keys in 'app' format cannot be found.
|
||||
|
||||
virtual mork_bool
|
||||
ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
// ProbeMapIsKeyNil() must say whether the representation of logical 'nil'
|
||||
// is currently found inside the key at ioMapKey, for a key found within
|
||||
// the map. The the map iterator uses this method to find map keys that
|
||||
// are actually being used for valid map associations; otherwise the
|
||||
// iterator cannot determine which map slots actually denote used keys.
|
||||
// The default method version returns true if all the bits equal zero.
|
||||
|
||||
virtual void
|
||||
ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
// ProbeMapClearKey() must put some representation of logical 'nil' into
|
||||
// every key slot in the map, such that MapTest() will later recognize
|
||||
// that this bit pattern shows each key slot is not actually being used.
|
||||
//
|
||||
// This method is typically called whenever the map is either created or
|
||||
// grown into a larger size, where ioMapKey is a pointer to an array of
|
||||
// inKeyCount keys, where each key is this->MapKeySize() bytes in size.
|
||||
// Note that keys are assumed immediately adjacent with no padding, so
|
||||
// if any alignment requirements must be met, then subclasses should have
|
||||
// already accounted for this when specifying a key size in the map.
|
||||
//
|
||||
// Since this method will be called when a map is being grown in size,
|
||||
// nothing should be assumed about the state slots of the map, since the
|
||||
// ioMapKey array might not yet live in sMap_Keys, and the array length
|
||||
// inKeyCount might not yet live in sMap_Slots. However, the value kept
|
||||
// in sMap_KeySize never changes, so this->MapKeySize() is always correct.
|
||||
|
||||
virtual void
|
||||
ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
// This method actually puts keys and vals in the map in suitable format.
|
||||
//
|
||||
// ProbeMapPushIn() must copy a caller key and value in 'app' format
|
||||
// into the map slots provided, which are in 'map' format. When the
|
||||
// 'app' and 'map' formats are identical, then this is just a bitwise
|
||||
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
|
||||
// and this is exactly what the default implementation performs. However,
|
||||
// if 'app' and 'map' formats are different, and MapTest() depends on this
|
||||
// difference in format, then subclasses must override this method to do
|
||||
// whatever is necessary to store the input app key in output map format.
|
||||
//
|
||||
// Do NOT write more than this->MapKeySize() bytes of a map key, or more
|
||||
// than this->MapValSize() bytes of a map val, or corruption might ensue.
|
||||
//
|
||||
// The inAppKey and inAppVal parameters are the same ones passed into a
|
||||
// call to MapAtPut(), and the outMapKey and outMapVal parameters are ones
|
||||
// determined by how the map currently positions key inAppKey in the map.
|
||||
//
|
||||
// Note any key or val parameter can be a null pointer, in which case
|
||||
// this method must do nothing with those parameters. In particular, do
|
||||
// no key move at all when either inAppKey or outMapKey is nil, and do
|
||||
// no val move at all when either inAppVal or outMapVal is nil. Note that
|
||||
// outMapVal should always be nil when this->MapValSize() is nil.
|
||||
|
||||
virtual void
|
||||
ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// This method actually gets keys and vals from the map in suitable format.
|
||||
//
|
||||
// ProbeMapPullOut() must copy a key and val in 'map' format into the
|
||||
// caller key and val slots provided, which are in 'app' format. When the
|
||||
// 'app' and 'map' formats are identical, then this is just a bitwise
|
||||
// copy of this->MapKeySize() key bytes and this->MapValSize() val bytes,
|
||||
// and this is exactly what the default implementation performs. However,
|
||||
// if 'app' and 'map' formats are different, and MapTest() depends on this
|
||||
// difference in format, then subclasses must override this method to do
|
||||
// whatever is necessary to store the input map key in output app format.
|
||||
//
|
||||
// The outAppKey and outAppVal parameters are the same ones passed into a
|
||||
// call to either MapAtPut() or MapAt(), while inMapKey and inMapVal are
|
||||
// determined by how the map currently positions the target key in the map.
|
||||
//
|
||||
// Note any key or val parameter can be a null pointer, in which case
|
||||
// this method must do nothing with those parameters. In particular, do
|
||||
// no key move at all when either inMapKey or outAppKey is nil, and do
|
||||
// no val move at all when either inMapVal or outAppVal is nil. Note that
|
||||
// inMapVal should always be nil when this->MapValSize() is nil.
|
||||
|
||||
// } ===== end morkProbeMap methods =====
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseProbeMap() only if open
|
||||
virtual ~morkProbeMap(); // assert that CloseProbeMap() executed earlier
|
||||
|
||||
public: // morkProbeMap construction & destruction
|
||||
morkProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap,
|
||||
mork_size inKeySize, mork_size inValSize,
|
||||
nsIMdbHeap* ioMapHeap, mork_size inSlots,
|
||||
mork_bool inZeroIsClearKey);
|
||||
|
||||
void CloseProbeMap(morkEnv* ev); // called by
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsProbeMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kProbeMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongMap(morkMap* me,
|
||||
morkEnv* ev, morkMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
/* morkProbeMapIter */
|
||||
|
||||
#define morkProbeMapIter_kBeforeIx ((mork_i4) -1) /* before first member */
|
||||
#define morkProbeMapIter_kAfterIx ((mork_i4) -2) /* after last member */
|
||||
|
||||
class morkProbeMapIter {
|
||||
|
||||
protected:
|
||||
morkProbeMap* sProbeMapIter_Map; // nonref
|
||||
mork_num sProbeMapIter_Seed; // iter's cached copy of map's seed
|
||||
|
||||
mork_i4 sProbeMapIter_HereIx;
|
||||
|
||||
mork_change sProbeMapIter_Change; // morkMapIter API simulation dummy
|
||||
mork_u1 sProbeMapIter_Pad[ 3 ]; // for u4 alignment
|
||||
|
||||
public:
|
||||
morkProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
|
||||
void CloseMapIter(morkEnv* ev);
|
||||
|
||||
morkProbeMapIter( ); // zero most slots; caller must call InitProbeMapIter()
|
||||
|
||||
protected: // protected so subclasses must provide suitable typesafe inlines:
|
||||
|
||||
void InitProbeMapIter(morkEnv* ev, morkProbeMap* ioMap);
|
||||
|
||||
void InitMapIter(morkEnv* ev, morkProbeMap* ioMap) // morkMapIter compatibility
|
||||
{ this->InitProbeMapIter(ev, ioMap); }
|
||||
|
||||
mork_bool IterFirst(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_bool IterNext(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_bool IterHere(morkEnv* ev, void* outKey, void* outVal);
|
||||
|
||||
// NOTE: the following methods ONLY work for sMap_ValIsIP pointer values.
|
||||
// (Note the implied assumption that zero is never a good value pattern.)
|
||||
|
||||
void* IterFirstVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterFirst(ev, outKey, &v); return v; }
|
||||
|
||||
void* IterNextVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterNext(ev, outKey, &v); return v; }
|
||||
|
||||
void* IterHereVal(morkEnv* ev, void* outKey);
|
||||
// equivalent to { void* v=0; this->IterHere(ev, outKey, &v); return v; }
|
||||
|
||||
// NOTE: the following methods ONLY work for sMap_KeyIsIP pointer values.
|
||||
// (Note the implied assumption that zero is never a good key pattern.)
|
||||
|
||||
void* IterFirstKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterFirst(ev, &k, 0); return k; }
|
||||
|
||||
void* IterNextKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterNext(ev, &k, 0); return k; }
|
||||
|
||||
void* IterHereKey(morkEnv* ev);
|
||||
// equivalent to { void* k=0; this->IterHere(ev, &k, 0); return k; }
|
||||
|
||||
public: // simulation of the morkMapIter API for morkMap compatibility:
|
||||
mork_change* First(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Next(morkEnv* ev, void* outKey, void* outVal);
|
||||
mork_change* Here(morkEnv* ev, void* outKey, void* outVal);
|
||||
|
||||
mork_change* CutHere(morkEnv* ev, void* outKey, void* outVal);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKPROBEMAP_ */
|
|
@ -0,0 +1,187 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* We need this because Solaris' version of qsort is broken and
|
||||
* causes array bounds reads.
|
||||
*/
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKQUICKSORT_
|
||||
#include "morkQuickSort.h"
|
||||
#endif
|
||||
|
||||
#if !defined(DEBUG) && (defined(__cplusplus) || defined(__gcc))
|
||||
# ifndef INLINE
|
||||
# define INLINE inline
|
||||
# endif
|
||||
#else
|
||||
# define INLINE
|
||||
#endif
|
||||
|
||||
static INLINE mork_u1*
|
||||
morkQS_med3(mork_u1 *, mork_u1 *, mork_u1 *, mdbAny_Order, void *);
|
||||
|
||||
static INLINE void
|
||||
morkQS_swapfunc(mork_u1 *, mork_u1 *, int, int);
|
||||
|
||||
/*
|
||||
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
|
||||
*/
|
||||
#define morkQS_swapcode(TYPE, parmi, parmj, n) { \
|
||||
long i = (n) / sizeof (TYPE); \
|
||||
register TYPE *pi = (TYPE *) (parmi); \
|
||||
register TYPE *pj = (TYPE *) (parmj); \
|
||||
do { \
|
||||
register TYPE t = *pi; \
|
||||
*pi++ = *pj; \
|
||||
*pj++ = t; \
|
||||
} while (--i > 0); \
|
||||
}
|
||||
|
||||
#define morkQS_SwapInit(a, es) swaptype = (a - (mork_u1 *)0) % sizeof(long) || \
|
||||
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
|
||||
|
||||
static INLINE void
|
||||
morkQS_swapfunc(mork_u1* a, mork_u1* b, int n, int swaptype)
|
||||
{
|
||||
if(swaptype <= 1)
|
||||
morkQS_swapcode(long, a, b, n)
|
||||
else
|
||||
morkQS_swapcode(mork_u1, a, b, n)
|
||||
}
|
||||
|
||||
#define morkQS_swap(a, b) \
|
||||
if (swaptype == 0) { \
|
||||
long t = *(long *)(a); \
|
||||
*(long *)(a) = *(long *)(b); \
|
||||
*(long *)(b) = t; \
|
||||
} else \
|
||||
morkQS_swapfunc(a, b, (int)inSize, swaptype)
|
||||
|
||||
#define morkQS_vecswap(a, b, n) if ((n) > 0) morkQS_swapfunc(a, b, (int)n, swaptype)
|
||||
|
||||
static INLINE mork_u1 *
|
||||
morkQS_med3(mork_u1* a, mork_u1* b, mork_u1* c, mdbAny_Order cmp, void* closure)
|
||||
{
|
||||
return (*cmp)(a, b, closure) < 0 ?
|
||||
((*cmp)(b, c, closure) < 0 ? b : ((*cmp)(a, c, closure) < 0 ? c : a ))
|
||||
:((*cmp)(b, c, closure) > 0 ? b : ((*cmp)(a, c, closure) < 0 ? a : c ));
|
||||
}
|
||||
|
||||
#define morkQS_MIN(x,y) ((x)<(y)?(x):(y))
|
||||
|
||||
void
|
||||
morkQuickSort(mork_u1* ioVec, mork_u4 inCount, mork_u4 inSize,
|
||||
mdbAny_Order inOrder, void* ioClosure)
|
||||
{
|
||||
mork_u1* pa, *pb, *pc, *pd, *pl, *pm, *pn;
|
||||
int d, r, swaptype, swap_cnt;
|
||||
|
||||
tailCall: morkQS_SwapInit(ioVec, inSize);
|
||||
swap_cnt = 0;
|
||||
if (inCount < 7) {
|
||||
for (pm = ioVec + inSize; pm < ioVec + inCount * inSize; pm += inSize)
|
||||
for (pl = pm; pl > ioVec && (*inOrder)(pl - inSize, pl, ioClosure) > 0;
|
||||
pl -= inSize)
|
||||
morkQS_swap(pl, pl - inSize);
|
||||
return;
|
||||
}
|
||||
pm = ioVec + (inCount / 2) * inSize;
|
||||
if (inCount > 7) {
|
||||
pl = ioVec;
|
||||
pn = ioVec + (inCount - 1) * inSize;
|
||||
if (inCount > 40) {
|
||||
d = (inCount / 8) * inSize;
|
||||
pl = morkQS_med3(pl, pl + d, pl + 2 * d, inOrder, ioClosure);
|
||||
pm = morkQS_med3(pm - d, pm, pm + d, inOrder, ioClosure);
|
||||
pn = morkQS_med3(pn - 2 * d, pn - d, pn, inOrder, ioClosure);
|
||||
}
|
||||
pm = morkQS_med3(pl, pm, pn, inOrder, ioClosure);
|
||||
}
|
||||
morkQS_swap(ioVec, pm);
|
||||
pa = pb = ioVec + inSize;
|
||||
|
||||
pc = pd = ioVec + (inCount - 1) * inSize;
|
||||
for (;;) {
|
||||
while (pb <= pc && (r = (*inOrder)(pb, ioVec, ioClosure)) <= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
morkQS_swap(pa, pb);
|
||||
pa += inSize;
|
||||
}
|
||||
pb += inSize;
|
||||
}
|
||||
while (pb <= pc && (r = (*inOrder)(pc, ioVec, ioClosure)) >= 0) {
|
||||
if (r == 0) {
|
||||
swap_cnt = 1;
|
||||
morkQS_swap(pc, pd);
|
||||
pd -= inSize;
|
||||
}
|
||||
pc -= inSize;
|
||||
}
|
||||
if (pb > pc)
|
||||
break;
|
||||
morkQS_swap(pb, pc);
|
||||
swap_cnt = 1;
|
||||
pb += inSize;
|
||||
pc -= inSize;
|
||||
}
|
||||
if (swap_cnt == 0) { /* Switch to insertion sort */
|
||||
for (pm = ioVec + inSize; pm < ioVec + inCount * inSize; pm += inSize)
|
||||
for (pl = pm; pl > ioVec && (*inOrder)(pl - inSize, pl, ioClosure) > 0;
|
||||
pl -= inSize)
|
||||
morkQS_swap(pl, pl - inSize);
|
||||
return;
|
||||
}
|
||||
|
||||
pn = ioVec + inCount * inSize;
|
||||
r = morkQS_MIN(pa - ioVec, pb - pa);
|
||||
morkQS_vecswap(ioVec, pb - r, r);
|
||||
r = morkQS_MIN(pd - pc, (int)(pn - pd - inSize));
|
||||
morkQS_vecswap(pb, pn - r, r);
|
||||
if ((r = pb - pa) > (int)inSize)
|
||||
morkQuickSort(ioVec, r / inSize, inSize, inOrder, ioClosure);
|
||||
if ((r = pd - pc) > (int)inSize) {
|
||||
/* Iterate rather than recurse to save stack space */
|
||||
ioVec = pn - r;
|
||||
inCount = r / inSize;
|
||||
goto tailCall;
|
||||
}
|
||||
/* morkQuickSort(pn - r, r / inSize, inSize, inOrder, ioClosure);*/
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKQUICKSORT_
|
||||
#define _MORKQUICKSORT_ 1
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
extern void
|
||||
morkQuickSort(mork_u1* ioVec, mork_u4 inCount, mork_u4 inSize,
|
||||
mdbAny_Order inOrder, void* ioClosure);
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKQUICKSORT_ */
|
|
@ -0,0 +1,965 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#include "morkRowSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#include "morkRowObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELLOBJECT_
|
||||
#include "morkCellObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWCELLCURSOR_
|
||||
#include "morkRowCellCursor.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
// notifications regarding row changes:
|
||||
|
||||
void morkRow::NoteRowAddCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kAdd);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kAdd);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowCutCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
mork_delta newDelta;
|
||||
morkDelta_Init(newDelta, inColumn, morkChange_kCut);
|
||||
|
||||
if ( newDelta != mRow_Delta ) // not repeating existing data?
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kCut);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetCol(morkEnv* ev, mork_column inColumn)
|
||||
{
|
||||
if ( !this->IsRowRewrite() )
|
||||
{
|
||||
if ( this->HasRowDelta() ) // already have one change recorded?
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
else
|
||||
this->SetRowDelta(inColumn, morkChange_kSet);
|
||||
}
|
||||
else
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
void morkRow::NoteRowSetAll(morkEnv* ev)
|
||||
{
|
||||
this->SetRowRewrite(); // just plan to write all row cells
|
||||
this->ClearRowDelta();
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::AddRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not already maxed out?
|
||||
++mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
mork_u2
|
||||
morkRow::CutRowGcUse(morkEnv* ev)
|
||||
{
|
||||
if ( this->IsRow() )
|
||||
{
|
||||
if ( mRow_GcUses ) // any outstanding uses to cut?
|
||||
{
|
||||
if ( mRow_GcUses < morkRow_kMaxGcUses ) // not frozen at max?
|
||||
--mRow_GcUses;
|
||||
}
|
||||
else
|
||||
this->GcUsesUnderflowWarning(ev);
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return mRow_GcUses;
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::GcUsesUnderflowWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("mRow_GcUses underflow");
|
||||
}
|
||||
|
||||
|
||||
/*static*/ void
|
||||
morkRow::NonRowTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkRow");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::NonRowTypeWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("non morkRow");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::LengthBeyondMaxError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mRow_Length over max");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::ZeroColumnError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError(" zero mork_column");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRow::NilCellsError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mRow_Cells");
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
|
||||
mork_size inLength, morkPool* ioPool)
|
||||
// if inLength is nonzero, cells will be allocated from ioPool
|
||||
{
|
||||
if ( ioSpace && ioPool && inOid )
|
||||
{
|
||||
if ( inLength <= morkRow_kMaxLength )
|
||||
{
|
||||
if ( inOid->mOid_Id != morkRow_kMinusOneRid )
|
||||
{
|
||||
mRow_Space = ioSpace;
|
||||
mRow_Object = 0;
|
||||
mRow_Cells = 0;
|
||||
mRow_Oid = *inOid;
|
||||
|
||||
mRow_Length = (mork_u2) inLength;
|
||||
mRow_Seed = (mork_u2) (mork_ip) this; // "random" assignment
|
||||
|
||||
mRow_GcUses = 0;
|
||||
mRow_Pad = 0;
|
||||
mRow_Flags = 0;
|
||||
mRow_Tag = morkRow_kTag;
|
||||
|
||||
morkZone* zone = &ioSpace->mSpace_Store->mStore_Zone;
|
||||
|
||||
if ( inLength )
|
||||
mRow_Cells = ioPool->NewCells(ev, inLength, zone);
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() ) // new row might dirty store
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
ioSpace->MinusOneRidError(ev);
|
||||
}
|
||||
else
|
||||
this->LengthBeyondMaxError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
morkRowObject*
|
||||
morkRow::AcquireRowObject(morkEnv* ev, morkStore* ioStore)
|
||||
{
|
||||
morkRowObject* ro = mRow_Object;
|
||||
if ( ro ) // need new row object?
|
||||
ro->AddRef();
|
||||
else
|
||||
{
|
||||
nsIMdbHeap* heap = ioStore->mPort_Heap;
|
||||
ro = new(*heap, ev)
|
||||
morkRowObject(ev, morkUsage::kHeap, heap, this, ioStore);
|
||||
if ( !ro )
|
||||
return (morkRowObject*) 0;
|
||||
|
||||
morkRowObject::SlotWeakRowObject(ro, ev, &mRow_Object);
|
||||
ro->AddRef();
|
||||
}
|
||||
return ro;
|
||||
}
|
||||
|
||||
nsIMdbRow*
|
||||
morkRow::AcquireRowHandle(morkEnv* ev, morkStore* ioStore)
|
||||
{
|
||||
return AcquireRowObject(ev, ioStore);
|
||||
}
|
||||
|
||||
nsIMdbCell*
|
||||
morkRow::AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
|
||||
mdb_column inCol, mork_pos inPos)
|
||||
{
|
||||
nsIMdbHeap* heap = ev->mEnv_Heap;
|
||||
morkCellObject* cellObj = new(*heap, ev)
|
||||
morkCellObject(ev, morkUsage::kHeap, heap, this, ioCell, inCol, inPos);
|
||||
if ( cellObj )
|
||||
{
|
||||
nsIMdbCell* cellHandle = cellObj->AcquireCellHandle(ev);
|
||||
// cellObj->CutStrongRef(ev->AsMdbEnv());
|
||||
return cellHandle;
|
||||
}
|
||||
return (nsIMdbCell*) 0;
|
||||
}
|
||||
|
||||
mork_count
|
||||
morkRow::CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill)
|
||||
// Count cells in ioVector that change existing cells in this row when
|
||||
// ioVector is added to the row (as in TakeCells()). This is the set
|
||||
// of cells with the same columns in ioVector and mRow_Cells, which do
|
||||
// not have exactly the same value in mCell_Atom, and which do not both
|
||||
// have change status equal to morkChange_kCut (because cutting a cut
|
||||
// cell still yields a cell that has been cut). CountOverlap() also
|
||||
// modifies the change attribute of any cell in ioVector to kDup when
|
||||
// the change was previously kCut and the same column cell was found
|
||||
// in this row with change also equal to kCut; this tells callers later
|
||||
// they need not look for that cell in the row again on a second pass.
|
||||
{
|
||||
mork_count outCount = 0;
|
||||
mork_pos pos = 0; // needed by GetCell()
|
||||
morkCell* cells = ioVector;
|
||||
morkCell* end = cells + inFill;
|
||||
--cells; // prepare for preincrement
|
||||
while ( ++cells < end && ev->Good() )
|
||||
{
|
||||
mork_column col = cells->GetColumn();
|
||||
|
||||
morkCell* old = this->GetCell(ev, col, &pos);
|
||||
if ( old ) // same column?
|
||||
{
|
||||
mork_change newChg = cells->GetChange();
|
||||
mork_change oldChg = old->GetChange();
|
||||
if ( newChg != morkChange_kCut || oldChg != newChg ) // not cut+cut?
|
||||
{
|
||||
if ( cells->mCell_Atom != old->mCell_Atom ) // not same atom?
|
||||
++outCount; // cells will replace old significantly when added
|
||||
}
|
||||
else
|
||||
cells->SetColumnAndChange(col, morkChange_kDup); // note dup status
|
||||
}
|
||||
}
|
||||
return outCount;
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::MergeCells(morkEnv* ev, morkCell* ioVector,
|
||||
mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap)
|
||||
// MergeCells() is the part of TakeCells() that does the insertion.
|
||||
// inOldRowFill is the old value of mRow_Length, and inOverlap is the
|
||||
// number of cells in the intersection that must be updated.
|
||||
{
|
||||
morkCell* newCells = mRow_Cells + inOldRowFill; // 1st new cell in row
|
||||
morkCell* newEnd = newCells + mRow_Length; // one past last cell
|
||||
|
||||
morkCell* srcCells = ioVector;
|
||||
morkCell* srcEnd = srcCells + inVecLength;
|
||||
|
||||
--srcCells; // prepare for preincrement
|
||||
while ( ++srcCells < srcEnd && ev->Good() )
|
||||
{
|
||||
mork_change srcChg = srcCells->GetChange();
|
||||
if ( srcChg != morkChange_kDup ) // anything to be done?
|
||||
{
|
||||
morkCell* dstCell = 0;
|
||||
if ( inOverlap )
|
||||
{
|
||||
mork_pos pos = 0; // needed by GetCell()
|
||||
dstCell = this->GetCell(ev, srcCells->GetColumn(), &pos);
|
||||
}
|
||||
if ( dstCell )
|
||||
{
|
||||
--inOverlap; // one fewer intersections to resolve
|
||||
// swap the atoms in the cells to avoid ref counting here:
|
||||
morkAtom* dstAtom = dstCell->mCell_Atom;
|
||||
*dstCell = *srcCells; // bitwise copy, taking src atom
|
||||
srcCells->mCell_Atom = dstAtom; // forget cell ref, if any
|
||||
}
|
||||
else if ( newCells < newEnd ) // another new cell exists?
|
||||
{
|
||||
dstCell = newCells++; // alloc another new cell
|
||||
// take atom from source cell, transferring ref to this row:
|
||||
*dstCell = *srcCells; // bitwise copy, taking src atom
|
||||
srcCells->mCell_Atom = 0; // forget cell ref, if any
|
||||
}
|
||||
else // oops, we ran out...
|
||||
ev->NewError("out of new cells");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
|
||||
morkStore* ioStore)
|
||||
{
|
||||
if ( ioVector && inVecLength && ev->Good() )
|
||||
{
|
||||
++mRow_Seed; // intend to change structure of mRow_Cells
|
||||
mork_size length = (mork_size) mRow_Length;
|
||||
|
||||
mork_count overlap = this->CountOverlap(ev, ioVector, inVecLength);
|
||||
|
||||
mork_size growth = inVecLength - overlap; // cells to add
|
||||
mork_size newLength = length + growth;
|
||||
|
||||
if ( growth && ev->Good() ) // need to add any cells?
|
||||
{
|
||||
morkZone* zone = &ioStore->mStore_Zone;
|
||||
morkPool* pool = ioStore->StorePool();
|
||||
if ( !pool->AddRowCells(ev, this, length + growth, zone) )
|
||||
ev->NewError("cannot take cells");
|
||||
}
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( mRow_Length >= newLength )
|
||||
this->MergeCells(ev, ioVector, inVecLength, length, overlap);
|
||||
else
|
||||
ev->NewError("not enough new cells");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool morkRow::MaybeDirtySpaceStoreAndRow()
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
rowSpace->mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( rowSpace->mSpace_CanDirty )
|
||||
{
|
||||
this->SetRowDirty();
|
||||
rowSpace->SetRowSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
morkCell*
|
||||
morkRow::NewCell(morkEnv* ev, mdb_column inColumn,
|
||||
mork_pos* outPos, morkStore* ioStore)
|
||||
{
|
||||
++mRow_Seed; // intend to change structure of mRow_Cells
|
||||
mork_size length = (mork_size) mRow_Length;
|
||||
*outPos = (mork_pos) length;
|
||||
morkPool* pool = ioStore->StorePool();
|
||||
morkZone* zone = &ioStore->mStore_Zone;
|
||||
|
||||
mork_bool canDirty = this->MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
if ( pool->AddRowCells(ev, this, length + 1, zone) )
|
||||
{
|
||||
morkCell* cell = mRow_Cells + length;
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
if ( canDirty )
|
||||
cell->SetCellColumnDirty(inColumn);
|
||||
else
|
||||
cell->SetCellColumnClean(inColumn);
|
||||
|
||||
if ( canDirty && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
return (morkCell*) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void morkRow::SeekColumn(morkEnv* ev, mdb_pos inPos,
|
||||
mdb_column* outColumn, mdbYarn* outYarn)
|
||||
{
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells && inPos < mRow_Length && inPos >= 0 )
|
||||
{
|
||||
morkCell* c = cells + inPos;
|
||||
if ( outColumn )
|
||||
*outColumn = c->GetColumn();
|
||||
if ( outYarn )
|
||||
c->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( outColumn )
|
||||
*outColumn = 0;
|
||||
if ( outYarn )
|
||||
((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::NextColumn(morkEnv* ev, mdb_column* ioColumn, mdbYarn* outYarn)
|
||||
{
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
mork_column last = 0;
|
||||
mork_column inCol = *ioColumn;
|
||||
morkCell* end = cells + mRow_Length;
|
||||
while ( cells < end )
|
||||
{
|
||||
if ( inCol == last ) // found column?
|
||||
{
|
||||
if ( outYarn )
|
||||
cells->mCell_Atom->GetYarn(outYarn); // nil atom works okay here
|
||||
*ioColumn = cells->GetColumn();
|
||||
return; // stop, we are done
|
||||
}
|
||||
else
|
||||
{
|
||||
last = cells->GetColumn();
|
||||
++cells;
|
||||
}
|
||||
}
|
||||
}
|
||||
*ioColumn = 0;
|
||||
if ( outYarn )
|
||||
((morkAtom*) 0)->GetYarn(outYarn); // yes this will work
|
||||
}
|
||||
|
||||
morkCell*
|
||||
morkRow::CellAt(morkEnv* ev, mork_pos inPos) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells && inPos < mRow_Length && inPos >= 0 )
|
||||
{
|
||||
return cells + inPos;
|
||||
}
|
||||
return (morkCell*) 0;
|
||||
}
|
||||
|
||||
morkCell*
|
||||
morkRow::GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
morkCell* end = cells + mRow_Length;
|
||||
while ( cells < end )
|
||||
{
|
||||
mork_column col = cells->GetColumn();
|
||||
if ( col == inColumn ) // found the desired column?
|
||||
{
|
||||
*outPos = cells - mRow_Cells;
|
||||
return cells;
|
||||
}
|
||||
else
|
||||
++cells;
|
||||
}
|
||||
}
|
||||
*outPos = -1;
|
||||
return (morkCell*) 0;
|
||||
}
|
||||
|
||||
mork_aid
|
||||
morkRow::GetCellAtomAid(morkEnv* ev, mdb_column inColumn) const
|
||||
// GetCellAtomAid() finds the cell with column inColumn, and sees if the
|
||||
// atom has a token ID, and returns the atom's ID if there is one. Or
|
||||
// else zero is returned if there is no such column, or no atom, or if
|
||||
// the atom has no ID to return. This method is intended to support
|
||||
// efficient updating of column indexes for rows in a row space.
|
||||
{
|
||||
if ( this && this->IsRow() )
|
||||
{
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
morkCell* end = cells + mRow_Length;
|
||||
while ( cells < end )
|
||||
{
|
||||
mork_column col = cells->GetColumn();
|
||||
if ( col == inColumn ) // found desired column?
|
||||
{
|
||||
morkAtom* atom = cells->mCell_Atom;
|
||||
if ( atom && atom->IsBook() )
|
||||
return ((morkBookAtom*) atom)->mBookAtom_Id;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
++cells;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonRowTypeError(ev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::EmptyAllCells(morkEnv* ev)
|
||||
{
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkPool* pool = store->StorePool();
|
||||
morkCell* end = cells + mRow_Length;
|
||||
--cells; // prepare for preincrement:
|
||||
while ( ++cells < end )
|
||||
{
|
||||
if ( cells->mCell_Atom )
|
||||
cells->SetAtom(ev, (morkAtom*) 0, pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::cut_all_index_entries(morkEnv* ev)
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
|
||||
{
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
morkCell* end = cells + mRow_Length;
|
||||
--cells; // prepare for preincrement:
|
||||
while ( ++cells < end )
|
||||
{
|
||||
morkAtom* atom = cells->mCell_Atom;
|
||||
if ( atom )
|
||||
{
|
||||
mork_aid atomAid = atom->GetBookAtomAid();
|
||||
if ( atomAid )
|
||||
{
|
||||
mork_column col = cells->GetColumn();
|
||||
morkAtomRowMap* map = rowSpace->FindMap(ev, col);
|
||||
if ( map ) // cut row from index for this column?
|
||||
map->CutAid(ev, atomAid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::CutAllColumns(morkEnv* ev)
|
||||
{
|
||||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace->mRowSpace_IndexCount ) // any indexes?
|
||||
this->cut_all_index_entries(ev);
|
||||
|
||||
morkPool* pool = store->StorePool();
|
||||
pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::SetRow(morkEnv* ev, const morkRow* inSourceRow)
|
||||
{
|
||||
// note inSourceRow might be in another DB, with a different store...
|
||||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
morkStore* srcStore = inSourceRow->GetRowSpaceStore(ev);
|
||||
if ( store && srcStore )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
mork_count indexes = rowSpace->mRowSpace_IndexCount; // any indexes?
|
||||
|
||||
mork_bool sameStore = ( store == srcStore ); // identical stores?
|
||||
morkPool* pool = store->StorePool();
|
||||
if ( pool->CutRowCells(ev, this, /*newSize*/ 0, &store->mStore_Zone) )
|
||||
{
|
||||
mork_fill fill = inSourceRow->mRow_Length;
|
||||
if ( pool->AddRowCells(ev, this, fill, &store->mStore_Zone) )
|
||||
{
|
||||
morkCell* dst = mRow_Cells;
|
||||
morkCell* dstEnd = dst + mRow_Length;
|
||||
|
||||
const morkCell* src = inSourceRow->mRow_Cells;
|
||||
const morkCell* srcEnd = src + fill;
|
||||
--dst; --src; // prepare both for preincrement:
|
||||
|
||||
while ( ++dst < dstEnd && ++src < srcEnd && ev->Good() )
|
||||
{
|
||||
morkAtom* atom = src->mCell_Atom;
|
||||
mork_column dstCol = src->GetColumn();
|
||||
// Note we modify the mCell_Atom slot directly instead of using
|
||||
// morkCell::SetAtom(), because we know it starts equal to nil.
|
||||
|
||||
if ( sameStore ) // source and dest in same store?
|
||||
{
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref to non-nil atom?
|
||||
atom->AddCellUse(ev);
|
||||
}
|
||||
else // need to dup items from src store in a dest store
|
||||
{
|
||||
dstCol = store->CopyToken(ev, dstCol, srcStore);
|
||||
if ( dstCol )
|
||||
{
|
||||
// next line equivalent to inline morkCell::SetCellDirty():
|
||||
dst->SetCellColumnDirty(dstCol);
|
||||
atom = store->CopyAtom(ev, atom);
|
||||
dst->mCell_Atom = atom;
|
||||
if ( atom ) // another ref?
|
||||
atom->AddCellUse(ev);
|
||||
}
|
||||
}
|
||||
if ( indexes && atom )
|
||||
{
|
||||
mork_aid atomAid = atom->GetBookAtomAid();
|
||||
if ( atomAid )
|
||||
{
|
||||
morkAtomRowMap* map = rowSpace->FindMap(ev, dstCol);
|
||||
if ( map )
|
||||
map->AddAid(ev, atomAid, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::AddRow(morkEnv* ev, const morkRow* inSourceRow)
|
||||
{
|
||||
if ( mRow_Length ) // any existing cells we might need to keep?
|
||||
{
|
||||
ev->StubMethodOnlyError();
|
||||
}
|
||||
else
|
||||
this->SetRow(ev, inSourceRow); // just exactly duplicate inSourceRow
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::OnZeroRowGcUse(morkEnv* ev)
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
// ev->NewWarning("need to implement OnZeroRowGcUse");
|
||||
}
|
||||
|
||||
void
|
||||
morkRow::DirtyAllRowContent(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() )
|
||||
{
|
||||
this->SetRowRewrite();
|
||||
this->NoteRowSetAll(ev);
|
||||
}
|
||||
morkCell* cells = mRow_Cells;
|
||||
if ( cells )
|
||||
{
|
||||
morkCell* end = cells + mRow_Length;
|
||||
--cells; // prepare for preincrement:
|
||||
while ( ++cells < end )
|
||||
{
|
||||
cells->SetCellDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
morkStore*
|
||||
morkRow::GetRowSpaceStore(morkEnv* ev) const
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
if ( rowSpace )
|
||||
{
|
||||
morkStore* store = rowSpace->mSpace_Store;
|
||||
if ( store )
|
||||
{
|
||||
if ( store->IsStore() )
|
||||
{
|
||||
return store;
|
||||
}
|
||||
else
|
||||
store->NonStoreTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return (morkStore*) 0;
|
||||
}
|
||||
|
||||
void morkRow::CutColumn(morkEnv* ev, mdb_column inColumn)
|
||||
{
|
||||
mork_pos pos = -1;
|
||||
morkCell* cell = this->GetCell(ev, inColumn, &pos);
|
||||
if ( cell )
|
||||
{
|
||||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowCutCol(ev, inColumn);
|
||||
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
|
||||
if ( map ) // this row attribute is indexed by row space?
|
||||
{
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
if ( oldAtom ) // need to cut an entry from the index?
|
||||
{
|
||||
mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
if ( oldAid ) // cut old row attribute from row index in space?
|
||||
map->CutAid(ev, oldAid);
|
||||
}
|
||||
}
|
||||
|
||||
morkPool* pool = store->StorePool();
|
||||
cell->SetAtom(ev, (morkAtom*) 0, pool);
|
||||
|
||||
mork_fill fill = mRow_Length; // should not be zero
|
||||
MORK_ASSERT(fill);
|
||||
if ( fill ) // index < fill for last cell exists?
|
||||
{
|
||||
mork_fill last = fill - 1; // index of last cell in row
|
||||
|
||||
if ( pos < (mork_pos)last ) // need to move cells following cut cell?
|
||||
{
|
||||
morkCell* lastCell = mRow_Cells + last;
|
||||
mork_count after = last - pos; // cell count after cut cell
|
||||
morkCell* next = cell + 1; // next cell after cut cell
|
||||
MORK_MEMMOVE(cell, next, after * sizeof(morkCell));
|
||||
lastCell->SetColumnAndChange(0, 0);
|
||||
lastCell->mCell_Atom = 0;
|
||||
}
|
||||
|
||||
if ( ev->Good() )
|
||||
pool->CutRowCells(ev, this, fill - 1, &store->mStore_Zone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
morkAtom* morkRow::GetColumnAtom(morkEnv* ev, mdb_column inColumn)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mork_pos pos = -1;
|
||||
morkCell* cell = this->GetCell(ev, inColumn, &pos);
|
||||
if ( cell )
|
||||
return cell->mCell_Atom;
|
||||
}
|
||||
return (morkAtom*) 0;
|
||||
}
|
||||
|
||||
void morkRow::AddColumn(morkEnv* ev, mdb_column inColumn,
|
||||
const mdbYarn* inYarn, morkStore* ioStore)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mork_pos pos = -1;
|
||||
morkCell* cell = this->GetCell(ev, inColumn, &pos);
|
||||
morkCell* oldCell = cell; // need to know later whether new
|
||||
if ( !cell ) // column does not yet exist?
|
||||
cell = this->NewCell(ev, inColumn, &pos, ioStore);
|
||||
|
||||
if ( cell )
|
||||
{
|
||||
morkAtom* oldAtom = cell->mCell_Atom;
|
||||
|
||||
morkAtom* atom = ioStore->YarnToAtom(ev, inYarn, PR_TRUE /* create */);
|
||||
if ( atom && atom != oldAtom )
|
||||
{
|
||||
morkRowSpace* rowSpace = mRow_Space;
|
||||
morkAtomRowMap* map = ( rowSpace->mRowSpace_IndexCount )?
|
||||
rowSpace->FindMap(ev, inColumn) : (morkAtomRowMap*) 0;
|
||||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
if ( oldAtom && oldAtom != atom ) // cut old cell from index?
|
||||
{
|
||||
mork_aid oldAid = oldAtom->GetBookAtomAid();
|
||||
if ( oldAid ) // cut old row attribute from row index in space?
|
||||
map->CutAid(ev, oldAid);
|
||||
}
|
||||
}
|
||||
|
||||
cell->SetAtom(ev, atom, ioStore->StorePool()); // refcounts atom
|
||||
|
||||
if ( oldCell ) // we changed a pre-existing cell in the row?
|
||||
{
|
||||
++mRow_Seed;
|
||||
if ( this->MaybeDirtySpaceStoreAndRow() && !this->IsRowRewrite() )
|
||||
this->NoteRowAddCol(ev, inColumn);
|
||||
}
|
||||
|
||||
if ( map ) // inColumn is indexed by row space?
|
||||
{
|
||||
mork_aid newAid = atom->GetBookAtomAid();
|
||||
if ( newAid ) // add new row attribute to row index in space?
|
||||
map->AddAid(ev, newAid, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
morkRowCellCursor*
|
||||
morkRow::NewRowCellCursor(morkEnv* ev, mdb_pos inPos)
|
||||
{
|
||||
morkRowCellCursor* outCursor = 0;
|
||||
if ( ev->Good() )
|
||||
{
|
||||
morkStore* store = this->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
morkRowObject* rowObj = this->AcquireRowObject(ev, store);
|
||||
if ( rowObj )
|
||||
{
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
morkRowCellCursor* cursor = new(*heap, ev)
|
||||
morkRowCellCursor(ev, morkUsage::kHeap, heap, rowObj);
|
||||
|
||||
if ( cursor )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
cursor->mRowCellCursor_Col = inPos;
|
||||
outCursor = cursor;
|
||||
}
|
||||
else
|
||||
cursor->CutStrongRef(ev->mEnv_SelfAsMdbEnv);
|
||||
}
|
||||
rowObj->Release(); // always cut ref (cursor has its own)
|
||||
}
|
||||
}
|
||||
}
|
||||
return outCursor;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#define _MORKROW_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELL_
|
||||
#include "morkCell.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbRow;
|
||||
class nsIMdbCell;
|
||||
#define morkDerived_kRow /*i*/ 0x5277 /* ascii 'Rw' */
|
||||
|
||||
#define morkRow_kMaxGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
#define morkRow_kMaxLength 0x0FFFF /* max for 16-bit unsigned int */
|
||||
#define morkRow_kMinusOneRid ((mork_rid) -1)
|
||||
|
||||
#define morkRow_kTag 'r' /* magic signature for mRow_Tag */
|
||||
|
||||
#define morkRow_kNotedBit ((mork_u1) (1 << 0)) /* space has change notes */
|
||||
#define morkRow_kRewriteBit ((mork_u1) (1 << 1)) /* must rewrite all cells */
|
||||
#define morkRow_kDirtyBit ((mork_u1) (1 << 2)) /* row has been changed */
|
||||
|
||||
class morkRow{ // row of cells
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkRowSpace* mRow_Space; // mRow_Space->SpaceScope() is the row scope
|
||||
morkRowObject* mRow_Object; // refcount & other state for object sharing
|
||||
morkCell* mRow_Cells;
|
||||
mdbOid mRow_Oid;
|
||||
|
||||
mork_delta mRow_Delta; // space to note a single column change
|
||||
|
||||
mork_u2 mRow_Length; // physical count of cells in mRow_Cells
|
||||
mork_u2 mRow_Seed; // count changes in mRow_Cells structure
|
||||
|
||||
mork_u1 mRow_GcUses; // persistent references from tables
|
||||
mork_u1 mRow_Pad; // for u1 alignment
|
||||
mork_u1 mRow_Flags; // one-byte flags slot
|
||||
mork_u1 mRow_Tag; // one-byte tag (need u4 alignment pad)
|
||||
|
||||
public: // interpreting mRow_Delta
|
||||
|
||||
mork_bool HasRowDelta() const { return ( mRow_Delta != 0 ); }
|
||||
|
||||
void ClearRowDelta() { mRow_Delta = 0; }
|
||||
|
||||
void SetRowDelta(mork_column inCol, mork_change inChange)
|
||||
{ morkDelta_Init(mRow_Delta, inCol, inChange); }
|
||||
|
||||
mork_column GetDeltaColumn() const { return morkDelta_Column(mRow_Delta); }
|
||||
mork_change GetDeltaChange() const { return morkDelta_Change(mRow_Delta); }
|
||||
|
||||
public: // noting row changes
|
||||
|
||||
void NoteRowSetAll(morkEnv* ev);
|
||||
void NoteRowSetCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowAddCol(morkEnv* ev, mork_column inCol);
|
||||
void NoteRowCutCol(morkEnv* ev, mork_column inCol);
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetRowNoted() { mRow_Flags |= morkRow_kNotedBit; }
|
||||
void SetRowRewrite() { mRow_Flags |= morkRow_kRewriteBit; }
|
||||
void SetRowDirty() { mRow_Flags |= morkRow_kDirtyBit; }
|
||||
|
||||
void ClearRowNoted() { mRow_Flags &= (mork_u1) ~morkRow_kNotedBit; }
|
||||
void ClearRowRewrite() { mRow_Flags &= (mork_u1) ~morkRow_kRewriteBit; }
|
||||
void SetRowClean() { mRow_Flags = 0; mRow_Delta = 0; }
|
||||
|
||||
mork_bool IsRowNoted() const
|
||||
{ return ( mRow_Flags & morkRow_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsRowRewrite() const
|
||||
{ return ( mRow_Flags & morkRow_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsRowClean() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) == 0; }
|
||||
|
||||
mork_bool IsRowDirty() const
|
||||
{ return ( mRow_Flags & morkRow_kDirtyBit ) != 0; }
|
||||
|
||||
mork_bool IsRowUsed() const
|
||||
{ return mRow_GcUses != 0; }
|
||||
|
||||
public: // other row methods
|
||||
morkRow( ) { }
|
||||
morkRow(const mdbOid* inOid) :mRow_Oid(*inOid) { }
|
||||
void InitRow(morkEnv* ev, const mdbOid* inOid, morkRowSpace* ioSpace,
|
||||
mork_size inLength, morkPool* ioPool);
|
||||
// if inLength is nonzero, cells will be allocated from ioPool
|
||||
|
||||
morkRowObject* AcquireRowObject(morkEnv* ev, morkStore* ioStore);
|
||||
nsIMdbRow* AcquireRowHandle(morkEnv* ev, morkStore* ioStore);
|
||||
nsIMdbCell* AcquireCellHandle(morkEnv* ev, morkCell* ioCell,
|
||||
mdb_column inColumn, mork_pos inPos);
|
||||
|
||||
mork_u2 AddRowGcUse(morkEnv* ev);
|
||||
mork_u2 CutRowGcUse(morkEnv* ev);
|
||||
|
||||
|
||||
mork_bool MaybeDirtySpaceStoreAndRow();
|
||||
|
||||
public: // internal row methods
|
||||
|
||||
void cut_all_index_entries(morkEnv* ev);
|
||||
|
||||
// void cut_cell_from_space_index(morkEnv* ev, morkCell* ioCell);
|
||||
|
||||
mork_count CountOverlap(morkEnv* ev, morkCell* ioVector, mork_fill inFill);
|
||||
// Count cells in ioVector that change existing cells in this row when
|
||||
// ioVector is added to the row (as in TakeCells()). This is the set
|
||||
// of cells with the same columns in ioVector and mRow_Cells, which do
|
||||
// not have exactly the same value in mCell_Atom, and which do not both
|
||||
// have change status equal to morkChange_kCut (because cutting a cut
|
||||
// cell still yields a cell that has been cut). CountOverlap() also
|
||||
// modifies the change attribute of any cell in ioVector to kDup when
|
||||
// the change was previously kCut and the same column cell was found
|
||||
// in this row with change also equal to kCut; this tells callers later
|
||||
// they need not look for that cell in the row again on a second pass.
|
||||
|
||||
void MergeCells(morkEnv* ev, morkCell* ioVector,
|
||||
mork_fill inVecLength, mork_fill inOldRowFill, mork_fill inOverlap);
|
||||
// MergeCells() is the part of TakeCells() that does the insertion.
|
||||
// inOldRowFill is the old value of mRow_Length, and inOverlap is the
|
||||
// number of cells in the intersection that must be updated.
|
||||
|
||||
void TakeCells(morkEnv* ev, morkCell* ioVector, mork_fill inVecLength,
|
||||
morkStore* ioStore);
|
||||
|
||||
morkCell* NewCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos,
|
||||
morkStore* ioStore);
|
||||
morkCell* GetCell(morkEnv* ev, mdb_column inColumn, mork_pos* outPos) const;
|
||||
morkCell* CellAt(morkEnv* ev, mork_pos inPos) const;
|
||||
|
||||
mork_aid GetCellAtomAid(morkEnv* ev, mdb_column inColumn) const;
|
||||
// GetCellAtomAid() finds the cell with column inColumn, and sees if the
|
||||
// atom has a token ID, and returns the atom's ID if there is one. Or
|
||||
// else zero is returned if there is no such column, or no atom, or if
|
||||
// the atom has no ID to return. This method is intended to support
|
||||
// efficient updating of column indexes for rows in a row space.
|
||||
|
||||
public: // external row methods
|
||||
|
||||
void DirtyAllRowContent(morkEnv* ev);
|
||||
|
||||
morkStore* GetRowSpaceStore(morkEnv* ev) const;
|
||||
|
||||
void AddColumn(morkEnv* ev, mdb_column inColumn,
|
||||
const mdbYarn* inYarn, morkStore* ioStore);
|
||||
|
||||
morkAtom* GetColumnAtom(morkEnv* ev, mdb_column inColumn);
|
||||
|
||||
void NextColumn(morkEnv* ev, mdb_column* ioColumn, mdbYarn* outYarn);
|
||||
|
||||
void SeekColumn(morkEnv* ev, mdb_pos inPos,
|
||||
mdb_column* outColumn, mdbYarn* outYarn);
|
||||
|
||||
void CutColumn(morkEnv* ev, mdb_column inColumn);
|
||||
|
||||
morkRowCellCursor* NewRowCellCursor(morkEnv* ev, mdb_pos inPos);
|
||||
|
||||
void EmptyAllCells(morkEnv* ev);
|
||||
void AddRow(morkEnv* ev, const morkRow* inSourceRow);
|
||||
void SetRow(morkEnv* ev, const morkRow* inSourceRow);
|
||||
void CutAllColumns(morkEnv* ev);
|
||||
|
||||
void OnZeroRowGcUse(morkEnv* ev);
|
||||
// OnZeroRowGcUse() is called when CutRowGcUse() returns zero.
|
||||
|
||||
public: // dynamic typing
|
||||
|
||||
mork_bool IsRow() const { return mRow_Tag == morkRow_kTag; }
|
||||
|
||||
public: // hash and equal
|
||||
|
||||
mork_u4 HashRow() const
|
||||
{
|
||||
return (mRow_Oid.mOid_Scope << 16) ^ mRow_Oid.mOid_Id;
|
||||
}
|
||||
|
||||
mork_bool EqualRow(const morkRow* ioRow) const
|
||||
{
|
||||
return
|
||||
(
|
||||
( mRow_Oid.mOid_Scope == ioRow->mRow_Oid.mOid_Scope )
|
||||
&& ( mRow_Oid.mOid_Id == ioRow->mRow_Oid.mOid_Id )
|
||||
);
|
||||
}
|
||||
|
||||
mork_bool EqualOid(const mdbOid* ioOid) const
|
||||
{
|
||||
return
|
||||
(
|
||||
( mRow_Oid.mOid_Scope == ioOid->mOid_Scope )
|
||||
&& ( mRow_Oid.mOid_Id == ioOid->mOid_Id )
|
||||
);
|
||||
}
|
||||
|
||||
public: // errors
|
||||
static void ZeroColumnError(morkEnv* ev);
|
||||
static void LengthBeyondMaxError(morkEnv* ev);
|
||||
static void NilCellsError(morkEnv* ev);
|
||||
static void NonRowTypeError(morkEnv* ev);
|
||||
static void NonRowTypeWarning(morkEnv* ev);
|
||||
static void GcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
private: // copying is not allowed
|
||||
morkRow(const morkRow& other);
|
||||
morkRow& operator=(const morkRow& other);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKROW_ */
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWCELLCURSOR_
|
||||
#include "morkRowCellCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#include "morkRowObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkRowCellCursor::CloseMorkNode(morkEnv* ev) // CloseRowCellCursor() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseRowCellCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkRowCellCursor::~morkRowCellCursor() // CloseRowCellCursor() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkRowCellCursor::morkRowCellCursor(morkEnv* ev,
|
||||
const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkRowObject* ioRowObject)
|
||||
: morkCursor(ev, inUsage, ioHeap)
|
||||
, mRowCellCursor_RowObject( 0 )
|
||||
, mRowCellCursor_Col( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioRowObject )
|
||||
{
|
||||
morkRow* row = ioRowObject->mRowObject_Row;
|
||||
if ( row )
|
||||
{
|
||||
if ( row->IsRow() )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
mCursor_Seed = row->mRow_Seed;
|
||||
|
||||
morkRowObject::SlotStrongRowObject(ioRowObject, ev,
|
||||
&mRowCellCursor_RowObject);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kRowCellCursor;
|
||||
}
|
||||
else
|
||||
row->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ioRowObject->NilRowError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkRowCellCursor, morkCursor, nsIMdbRowCellCursor)
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkRowCellCursor::CloseRowCellCursor(morkEnv* ev)
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
mCursor_Seed = 0;
|
||||
morkRowObject::SlotStrongRowObject((morkRowObject*) 0, ev,
|
||||
&mRowCellCursor_RowObject);
|
||||
this->CloseCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkRowCellCursor::NilRowObjectError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mRowCellCursor_RowObject");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowCellCursor::NonRowCellCursorTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkRowCellCursor");
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::SetRow(nsIMdbEnv* mev, nsIMdbRow* ioRow)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkRow* row = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
row = (morkRow *) ioRow;
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
{
|
||||
morkRowObject* rowObj = row->AcquireRowObject(ev, store);
|
||||
if ( rowObj )
|
||||
{
|
||||
morkRowObject::SlotStrongRowObject((morkRowObject*) 0, ev,
|
||||
&mRowCellCursor_RowObject);
|
||||
|
||||
mRowCellCursor_RowObject = rowObj; // take this strong ref
|
||||
mCursor_Seed = row->mRow_Seed;
|
||||
|
||||
row->GetCell(ev, mRowCellCursor_Col, &mCursor_Pos);
|
||||
}
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::GetRow(nsIMdbEnv* mev, nsIMdbRow** acqRow)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbRow* outRow = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkRowObject* rowObj = mRowCellCursor_RowObject;
|
||||
if ( rowObj )
|
||||
outRow = rowObj->AcquireRowHandle(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqRow )
|
||||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin cell creation methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::MakeCell( // get cell at current pos in the row
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos, // position of cell in row sequence
|
||||
nsIMdbCell** acqCell)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbCell* outCell = 0;
|
||||
mdb_pos pos = 0;
|
||||
mdb_column col = 0;
|
||||
morkRow* row = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
pos = mCursor_Pos;
|
||||
morkCell* cell = row->CellAt(ev, pos);
|
||||
if ( cell )
|
||||
{
|
||||
col = cell->GetColumn();
|
||||
outCell = row->AcquireCellHandle(ev, cell, col, pos);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqCell )
|
||||
*acqCell = outCell;
|
||||
if ( outPos )
|
||||
*outPos = pos;
|
||||
if ( outColumn )
|
||||
*outColumn = col;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end cell creation methods -----
|
||||
|
||||
// { ----- begin cell seeking methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::SeekCell( // same as SetRow() followed by MakeCell()
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_pos inPos, // position of cell in row sequence
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
nsIMdbCell** acqCell)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// } ----- end cell seeking methods -----
|
||||
|
||||
// { ----- begin cell iteration methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::NextCell( // get next cell in the row
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbCell** acqCell, // changes to the next cell in the iteration
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos)
|
||||
{
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
mdb_column col = 0;
|
||||
mdb_pos pos = mRowCellCursor_Col;
|
||||
if ( pos < 0 )
|
||||
pos = 0;
|
||||
else
|
||||
++pos;
|
||||
|
||||
morkCell* cell = mRowCellCursor_RowObject->mRowObject_Row->CellAt(ev, pos);
|
||||
if ( cell )
|
||||
{
|
||||
col = cell->GetColumn();
|
||||
*acqCell = mRowCellCursor_RowObject->mRowObject_Row->AcquireCellHandle(ev, cell, col, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
*acqCell = nsnull;
|
||||
pos = -1;
|
||||
}
|
||||
if ( outPos )
|
||||
*outPos = pos;
|
||||
if ( outColumn )
|
||||
*outColumn = col;
|
||||
|
||||
mRowCellCursor_Col = pos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowCellCursor::PickNextCell( // get next cell in row within filter set
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbCell* ioCell, // changes to the next cell in the iteration
|
||||
const mdbColumnSet* inFilterSet, // col set of actual caller interest
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos)
|
||||
// Note that inFilterSet should not have too many (many more than 10?)
|
||||
// cols, since this might imply a potential excessive consumption of time
|
||||
// over many cursor calls when looking for column and filter intersection.
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// } ----- end cell iteration methods -----
|
||||
|
||||
// } ===== end nsIMdbRowCellCursor methods =====
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKROWCELLCURSOR_
|
||||
#define _MORKROWCELLCURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class orkinRowCellCursor;
|
||||
#define morkDerived_kRowCellCursor /*i*/ 0x6343 /* ascii 'cC' */
|
||||
|
||||
class morkRowCellCursor : public morkCursor, public nsIMdbRowCellCursor { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkFactory* mObject_Factory; // weak ref to suite factory
|
||||
|
||||
// mork_seed mCursor_Seed;
|
||||
// mork_pos mCursor_Pos;
|
||||
// mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
// mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
morkRowObject* mRowCellCursor_RowObject; // strong ref to row
|
||||
mork_column mRowCellCursor_Col; // col of cell last at mCursor_Pos
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowCellCursor()
|
||||
virtual ~morkRowCellCursor(); // assert that close executed earlier
|
||||
|
||||
public: // morkRowCellCursor construction & destruction
|
||||
morkRowCellCursor(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkRowObject* ioRowObject);
|
||||
void CloseRowCellCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD SetRow(nsIMdbEnv* ev, nsIMdbRow* ioRow); // sets pos to -1
|
||||
NS_IMETHOD GetRow(nsIMdbEnv* ev, nsIMdbRow** acqRow);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin cell creation methods -----
|
||||
NS_IMETHOD MakeCell( // get cell at current pos in the row
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos, // position of cell in row sequence
|
||||
nsIMdbCell** acqCell); // the cell at inPos
|
||||
// } ----- end cell creation methods -----
|
||||
|
||||
// { ----- begin cell seeking methods -----
|
||||
NS_IMETHOD SeekCell( // same as SetRow() followed by MakeCell()
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inPos, // position of cell in row sequence
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
nsIMdbCell** acqCell); // the cell at inPos
|
||||
// } ----- end cell seeking methods -----
|
||||
|
||||
// { ----- begin cell iteration methods -----
|
||||
NS_IMETHOD NextCell( // get next cell in the row
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbCell** acqCell, // changes to the next cell in the iteration
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos); // position of cell in row sequence
|
||||
|
||||
NS_IMETHOD PickNextCell( // get next cell in row within filter set
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbCell* ioCell, // changes to the next cell in the iteration
|
||||
const mdbColumnSet* inFilterSet, // col set of actual caller interest
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdb_pos* outPos); // position of cell in row sequence
|
||||
|
||||
// Note that inFilterSet should not have too many (many more than 10?)
|
||||
// cols, since this might imply a potential excessive consumption of time
|
||||
// over many cursor calls when looking for column and filter intersection.
|
||||
// } ----- end cell iteration methods -----
|
||||
|
||||
|
||||
private: // copying is not allowed
|
||||
morkRowCellCursor(const morkRowCellCursor& other);
|
||||
morkRowCellCursor& operator=(const morkRowCellCursor& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsRowCellCursor() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kRowCellCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // errors
|
||||
static void NilRowObjectError(morkEnv* ev);
|
||||
static void NonRowCellCursorTypeError(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowCellCursor(morkRowCellCursor* me,
|
||||
morkEnv* ev, morkRowCellCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowCellCursor(morkRowCellCursor* me,
|
||||
morkEnv* ev, morkRowCellCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKROWCELLCURSOR_ */
|
|
@ -0,0 +1,339 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#include "morkRowMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkRowMap::CloseMorkNode(morkEnv* ev) // CloseRowMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseRowMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkRowMap::~morkRowMap() // assert CloseRowMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkRowMap::morkRowMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_size inSlots)
|
||||
: morkMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkRow*), /*inValSize*/ 0,
|
||||
inSlots, ioSlotHeap, /*inHoldChanges*/ morkBool_kFalse)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kRowMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkRowMap::CloseRowMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CloseMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
/*virtual*/ mork_bool //
|
||||
morkRowMap::Equal(morkEnv* ev, const void* inKeyA,
|
||||
const void* inKeyB) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkRow**) inKeyA)->EqualRow(*(const morkRow**) inKeyB);
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 //
|
||||
morkRowMap::Hash(morkEnv* ev, const void* inKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return (*(const morkRow**) inKey)->HashRow();
|
||||
}
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
|
||||
mork_bool
|
||||
morkRowMap::AddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->Put(ev, &ioRow, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowMap::CutOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
morkRow row(inOid);
|
||||
morkRow* key = &row;
|
||||
morkRow* oldKey = 0;
|
||||
this->Cut(ev, &key, &oldKey, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowMap::CutRow(morkEnv* ev, const morkRow* ioRow)
|
||||
{
|
||||
morkRow* oldKey = 0;
|
||||
this->Cut(ev, &ioRow, &oldKey, /*val*/ (void*) 0,
|
||||
(mork_change**) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowMap::GetOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
morkRow row(inOid);
|
||||
morkRow* key = &row;
|
||||
morkRow* oldKey = 0;
|
||||
this->Get(ev, &key, &oldKey, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowMap::GetRow(morkEnv* ev, const morkRow* ioRow)
|
||||
{
|
||||
morkRow* oldKey = 0;
|
||||
this->Get(ev, &ioRow, &oldKey, /*val*/ (void*) 0, (mork_change**) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkRowProbeMap::CloseMorkNode(morkEnv* ev) // CloseRowProbeMap() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseRowProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkRowProbeMap::~morkRowProbeMap() // assert CloseRowProbeMap() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkRowProbeMap::morkRowProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_size inSlots)
|
||||
: morkProbeMap(ev, inUsage, ioHeap,
|
||||
/*inKeySize*/ sizeof(morkRow*), /*inValSize*/ 0,
|
||||
ioSlotHeap, inSlots,
|
||||
/*inHoldChanges*/ morkBool_kTrue)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kRowProbeMap;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkRowProbeMap::CloseRowProbeMap(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
this->CloseProbeMap(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*virtual*/ mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
morkRowProbeMap::MapTest(morkEnv* ev, const void* inMapKey,
|
||||
const void* inAppKey) const
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
const morkRow* key = *(const morkRow**) inMapKey;
|
||||
if ( key )
|
||||
{
|
||||
mork_bool hit = key->EqualRow(*(const morkRow**) inAppKey);
|
||||
return ( hit ) ? morkTest_kHit : morkTest_kMiss;
|
||||
}
|
||||
else
|
||||
return morkTest_kVoid;
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
morkRowProbeMap::MapHash(morkEnv* ev, const void* inAppKey) const
|
||||
{
|
||||
const morkRow* key = *(const morkRow**) inAppKey;
|
||||
if ( key )
|
||||
return key->HashRow();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ mork_u4
|
||||
morkRowProbeMap::ProbeMapHashMapKey(morkEnv* ev,
|
||||
const void* inMapKey) const
|
||||
{
|
||||
const morkRow* key = *(const morkRow**) inMapKey;
|
||||
if ( key )
|
||||
return key->HashRow();
|
||||
else
|
||||
{
|
||||
ev->NilPointerWarning();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkRowProbeMap::AddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->MapAtPut(ev, &ioRow, /*val*/ (void*) 0,
|
||||
/*key*/ (void*) 0, /*val*/ (void*) 0);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowProbeMap::CutOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
MORK_USED_1(inOid);
|
||||
morkProbeMap::ProbeMapCutError(ev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowProbeMap::CutRow(morkEnv* ev, const morkRow* ioRow)
|
||||
{
|
||||
MORK_USED_1(ioRow);
|
||||
morkProbeMap::ProbeMapCutError(ev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowProbeMap::GetOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
morkRow row(inOid);
|
||||
morkRow* key = &row;
|
||||
morkRow* oldKey = 0;
|
||||
this->MapAt(ev, &key, &oldKey, /*val*/ (void*) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowProbeMap::GetRow(morkEnv* ev, const morkRow* ioRow)
|
||||
{
|
||||
morkRow* oldKey = 0;
|
||||
this->MapAt(ev, &ioRow, &oldKey, /*val*/ (void*) 0);
|
||||
|
||||
return oldKey;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,243 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#define _MORKROWMAP_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#include "morkProbeMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowMap /*i*/ 0x724D /* ascii 'rM' */
|
||||
|
||||
/*| morkRowMap: maps a set of morkRow by contained Oid
|
||||
|*/
|
||||
class morkRowMap : public morkMap { // for mapping row IDs to rows
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowMap() only if open
|
||||
virtual ~morkRowMap(); // assert that CloseRowMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkRowMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_size inSlots);
|
||||
void CloseRowMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsRowMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kRowMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkMap poly interface =====
|
||||
virtual mork_bool // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Equal(morkEnv* ev, const void* inKeyA, const void* inKeyB) const;
|
||||
// implemented using morkRow::EqualRow()
|
||||
|
||||
virtual mork_u4 // note: equal(a,b) implies hash(a) == hash(b)
|
||||
Hash(morkEnv* ev, const void* inKey) const;
|
||||
// implemented using morkRow::HashRow()
|
||||
// } ===== end morkMap poly interface =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddRow(morkEnv* ev, morkRow* ioRow);
|
||||
// AddRow() returns ev->Good()
|
||||
|
||||
morkRow* CutOid(morkEnv* ev, const mdbOid* inOid);
|
||||
// CutRid() returns the row removed equal to inRid, if there was one
|
||||
|
||||
morkRow* CutRow(morkEnv* ev, const morkRow* ioRow);
|
||||
// CutRow() returns the row removed equal to ioRow, if there was one
|
||||
|
||||
morkRow* GetOid(morkEnv* ev, const mdbOid* inOid);
|
||||
// GetOid() returns the row equal to inRid, or else nil
|
||||
|
||||
morkRow* GetRow(morkEnv* ev, const morkRow* ioRow);
|
||||
// GetRow() returns the row equal to ioRow, or else nil
|
||||
|
||||
// note the rows are owned elsewhere, usuall by morkRowSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowMap(morkRowMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowMap(morkRowMap* me,
|
||||
morkEnv* ev, morkRowMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
class morkRowMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkRowMapIter(morkEnv* ev, morkRowMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkRowMapIter( ) : morkMapIter() { }
|
||||
void InitRowMapIter(morkEnv* ev, morkRowMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change* FirstRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->First(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* NextRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->Next(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* HereRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->Here(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* CutHereRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->CutHere(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowProbeMap /*i*/ 0x726D /* ascii 'rm' */
|
||||
|
||||
/*| morkRowProbeMap: maps a set of morkRow by contained Oid
|
||||
|*/
|
||||
class morkRowProbeMap : public morkProbeMap { // for mapping row IDs to rows
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowProbeMap() only if open
|
||||
virtual ~morkRowProbeMap(); // assert CloseRowProbeMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkRowProbeMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_size inSlots);
|
||||
void CloseRowProbeMap(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsRowMap() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kRowMap; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkProbeMap methods =====
|
||||
virtual mork_test // hit(a,b) implies hash(a) == hash(b)
|
||||
MapTest(morkEnv* ev, const void* inMapKey, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 // hit(a,b) implies hash(a) == hash(b)
|
||||
MapHash(morkEnv* ev, const void* inAppKey) const;
|
||||
|
||||
virtual mork_u4 ProbeMapHashMapKey(morkEnv* ev, const void* inMapKey) const;
|
||||
|
||||
// virtual mork_bool ProbeMapIsKeyNil(morkEnv* ev, void* ioMapKey);
|
||||
|
||||
// virtual void ProbeMapClearKey(morkEnv* ev, // put 'nil' alls keys inside map
|
||||
// void* ioMapKey, mork_count inKeyCount); // array of keys inside map
|
||||
|
||||
// virtual void ProbeMapPushIn(morkEnv* ev, // move (key,val) into the map
|
||||
// const void* inAppKey, const void* inAppVal, // (key,val) outside map
|
||||
// void* outMapKey, void* outMapVal); // (key,val) inside map
|
||||
|
||||
// virtual void ProbeMapPullOut(morkEnv* ev, // move (key,val) out from the map
|
||||
// const void* inMapKey, const void* inMapVal, // (key,val) inside map
|
||||
// void* outAppKey, void* outAppVal) const; // (key,val) outside map
|
||||
// } ===== end morkProbeMap methods =====
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddRow(morkEnv* ev, morkRow* ioRow);
|
||||
// AddRow() returns ev->Good()
|
||||
|
||||
morkRow* CutOid(morkEnv* ev, const mdbOid* inOid);
|
||||
// CutRid() returns the row removed equal to inRid, if there was one
|
||||
|
||||
morkRow* CutRow(morkEnv* ev, const morkRow* ioRow);
|
||||
// CutRow() returns the row removed equal to ioRow, if there was one
|
||||
|
||||
morkRow* GetOid(morkEnv* ev, const mdbOid* inOid);
|
||||
// GetOid() returns the row equal to inRid, or else nil
|
||||
|
||||
morkRow* GetRow(morkEnv* ev, const morkRow* ioRow);
|
||||
// GetRow() returns the row equal to ioRow, or else nil
|
||||
|
||||
// note the rows are owned elsewhere, usuall by morkRowSpace
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowProbeMap(morkRowProbeMap* me,
|
||||
morkEnv* ev, morkRowProbeMap** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowProbeMap(morkRowProbeMap* me,
|
||||
morkEnv* ev, morkRowProbeMap** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
class morkRowProbeMapIter: public morkProbeMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkRowProbeMapIter(morkEnv* ev, morkRowProbeMap* ioMap)
|
||||
: morkProbeMapIter(ev, ioMap) { }
|
||||
|
||||
morkRowProbeMapIter( ) : morkProbeMapIter() { }
|
||||
void InitRowMapIter(morkEnv* ev, morkRowProbeMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change* FirstRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->First(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* NextRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->Next(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* HereRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->Here(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
|
||||
mork_change* CutHereRow(morkEnv* ev, morkRow** outRowPtr)
|
||||
{ return this->CutHere(ev, outRowPtr, /*val*/ (void*) 0); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKROWMAP_ */
|
|
@ -0,0 +1,660 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#include "morkRowObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWCELLCURSOR_
|
||||
#include "morkRowCellCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCELLOBJECT_
|
||||
#include "morkCellObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkRowObject::CloseMorkNode(morkEnv* ev) // CloseRowObject() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseRowObject(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkRowObject::~morkRowObject() // assert CloseRowObject() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkRowObject::morkRowObject(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
morkRow* ioRow, morkStore* ioStore)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mRowObject_Row( 0 )
|
||||
, mRowObject_Store( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioRow && ioStore )
|
||||
{
|
||||
mRowObject_Row = ioRow;
|
||||
mRowObject_Store = ioStore; // morkRowObjects don't ref-cnt the owning store.
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kRowObject;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkRowObject, morkObject, nsIMdbRow)
|
||||
// { ===== begin nsIMdbCollection methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetSeed(nsIMdbEnv* mev,
|
||||
mdb_seed* outSeed)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
*outSeed = (mdb_seed) mRowObject_Row->mRow_Seed;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetCount(nsIMdbEnv* mev,
|
||||
mdb_count* outCount)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
*outCount = (mdb_count) mRowObject_Row->mRow_Length;
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetPort(nsIMdbEnv* mev,
|
||||
nsIMdbPort** acqPort)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbPort* outPort = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkRowSpace* rowSpace = mRowObject_Row->mRow_Space;
|
||||
if ( rowSpace && rowSpace->mSpace_Store )
|
||||
{
|
||||
morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
outPort = store->AcquireStoreHandle(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqPort )
|
||||
*acqPort = outPort;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetCursor( // make a cursor starting iter at inMemberPos
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
|
||||
nsIMdbCursor** acqCursor)
|
||||
{
|
||||
return this->GetRowCellCursor(mev, inMemberPos,
|
||||
(nsIMdbRowCellCursor**) acqCursor);
|
||||
}
|
||||
// } ----- end cursor methods -----
|
||||
|
||||
// { ----- begin ID methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetOid(nsIMdbEnv* mev,
|
||||
mdbOid* outOid)
|
||||
{
|
||||
*outOid = mRowObject_Row->mRow_Oid;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
return (ev) ? ev->AsErr() : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::BecomeContent(nsIMdbEnv* mev,
|
||||
const mdbOid* inOid)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
// remember row->MaybeDirtySpaceStoreAndRow();
|
||||
}
|
||||
// } ----- end ID methods -----
|
||||
|
||||
// { ----- begin activity dropping methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::DropActivity( // tell collection usage no longer expected
|
||||
nsIMdbEnv* mev)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// } ----- end activity dropping methods -----
|
||||
|
||||
// } ===== end nsIMdbCollection methods =====
|
||||
|
||||
// { ===== begin nsIMdbRow methods =====
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetRowCellCursor( // make a cursor starting iteration at inCellPos
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_pos inPos, // zero-based ordinal position of cell in row
|
||||
nsIMdbRowCellCursor** acqCursor)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
nsIMdbRowCellCursor* outCursor = 0;
|
||||
if ( ev )
|
||||
{
|
||||
morkRowCellCursor* cursor = mRowObject_Row->NewRowCellCursor(ev, inPos);
|
||||
if ( cursor )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
cursor->mCursor_Seed = (mork_seed) inPos;
|
||||
outCursor = cursor;
|
||||
NS_ADDREF(cursor);
|
||||
}
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqCursor )
|
||||
*acqCursor = outCursor;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end cursor methods -----
|
||||
|
||||
// { ----- begin column methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::AddColumn( // make sure a particular column is inside row
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to add
|
||||
const mdbYarn* inYarn)
|
||||
{
|
||||
mdb_err outErr = NS_ERROR_FAILURE;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store && mRowObject_Row)
|
||||
mRowObject_Row->AddColumn(ev, inColumn, inYarn, mRowObject_Store);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::CutColumn( // make sure a column is absent from the row
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn)
|
||||
{
|
||||
mdb_err outErr = NS_ERROR_FAILURE;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
mRowObject_Row->CutColumn(ev, inColumn);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::CutAllColumns( // remove all columns from the row
|
||||
nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
mRowObject_Row->CutAllColumns(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end column methods -----
|
||||
|
||||
// { ----- begin cell methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::NewCell( // get cell for specified column, or add new one
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to add
|
||||
nsIMdbCell** acqCell)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
GetCell(mev, inColumn, acqCell);
|
||||
if ( !*acqCell )
|
||||
{
|
||||
if ( mRowObject_Store )
|
||||
{
|
||||
mdbYarn yarn; // to pass empty yarn into morkRowObject::AddColumn()
|
||||
yarn.mYarn_Buf = 0;
|
||||
yarn.mYarn_Fill = 0;
|
||||
yarn.mYarn_Size = 0;
|
||||
yarn.mYarn_More = 0;
|
||||
yarn.mYarn_Form = 0;
|
||||
yarn.mYarn_Grow = 0;
|
||||
AddColumn(ev, inColumn, &yarn);
|
||||
GetCell(mev, inColumn, acqCell);
|
||||
}
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::AddCell( // copy a cell from another row to this row
|
||||
nsIMdbEnv* mev, // context
|
||||
const nsIMdbCell* inCell)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkCell* cell = 0;
|
||||
morkCellObject* cellObj = (morkCellObject*) inCell;
|
||||
if ( cellObj->CanUseCell(mev, morkBool_kFalse, &outErr, &cell) )
|
||||
{
|
||||
|
||||
morkRow* cellRow = cellObj->mCellObject_Row;
|
||||
if ( cellRow )
|
||||
{
|
||||
if ( mRowObject_Row != cellRow )
|
||||
{
|
||||
morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
|
||||
morkStore* cellStore = cellRow->GetRowSpaceStore(ev);
|
||||
if ( store && cellStore )
|
||||
{
|
||||
mork_column col = cell->GetColumn();
|
||||
morkAtom* atom = cell->mCell_Atom;
|
||||
mdbYarn yarn;
|
||||
atom->AliasYarn(&yarn); // works even when atom is nil
|
||||
|
||||
if ( store != cellStore )
|
||||
col = store->CopyToken(ev, col, cellStore);
|
||||
if ( ev->Good() )
|
||||
AddColumn(ev, col, &yarn);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetCell( // find a cell in this row
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to find
|
||||
nsIMdbCell** acqCell)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbCell* outCell = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
|
||||
if ( ev )
|
||||
{
|
||||
if ( inColumn )
|
||||
{
|
||||
mork_pos pos = 0;
|
||||
morkCell* cell = mRowObject_Row->GetCell(ev, inColumn, &pos);
|
||||
if ( cell )
|
||||
{
|
||||
outCell = mRowObject_Row->AcquireCellHandle(ev, cell, inColumn, pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
mRowObject_Row->ZeroColumnError(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqCell )
|
||||
*acqCell = outCell;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::EmptyAllCells( // make all cells in row empty of content
|
||||
nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
EmptyAllCells(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end cell methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::AddRow( // add all cells in another row to this one
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow* ioSourceRow)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkRow* unsafeSource = (morkRow*) ioSourceRow; // unsafe cast
|
||||
// if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
|
||||
{
|
||||
mRowObject_Row->AddRow(ev, unsafeSource);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::SetRow( // make exact duplicate of another row
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow* ioSourceRow)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
morkRowObject *sourceObject = (morkRowObject *) ioSourceRow; // unsafe cast
|
||||
morkRow* unsafeSource = sourceObject->mRowObject_Row;
|
||||
// if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
|
||||
{
|
||||
mRowObject_Row->SetRow(ev, unsafeSource);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin blob methods -----
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::SetCellYarn( // synonym for AddColumn()
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to add
|
||||
const mdbYarn* inYarn)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store )
|
||||
AddColumn(ev, inColumn, inYarn);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::GetCellYarn(
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to read
|
||||
mdbYarn* outYarn) // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store && mRowObject_Row)
|
||||
{
|
||||
morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
|
||||
atom->GetYarn(outYarn);
|
||||
// note nil atom works and sets yarn correctly
|
||||
}
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::AliasCellYarn(
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_column inColumn, // column to alias
|
||||
mdbYarn* outYarn) // writes ALL yarn slots
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store && mRowObject_Row)
|
||||
{
|
||||
morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
|
||||
atom->AliasYarn(outYarn);
|
||||
// note nil atom works and sets yarn correctly
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::NextCellYarn(nsIMdbEnv* mev, // iterative version of GetCellYarn()
|
||||
mdb_column* ioColumn, // next column to read
|
||||
mdbYarn* outYarn) // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
//
|
||||
// The ioColumn argument is an inout parameter which initially contains the
|
||||
// last column accessed and returns the next column corresponding to the
|
||||
// content read into the yarn. Callers should start with a zero column
|
||||
// value to say 'no previous column', which causes the first column to be
|
||||
// read. Then the value returned in ioColumn is perfect for the next call
|
||||
// to NextCellYarn(), since it will then be the previous column accessed.
|
||||
// Callers need only examine the column token returned to see which cell
|
||||
// in the row is being read into the yarn. When no more columns remain,
|
||||
// and the iteration has ended, ioColumn will return a zero token again.
|
||||
// So iterating over cells starts and ends with a zero column token.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store && mRowObject_Row)
|
||||
mRowObject_Row->NextColumn(ev, ioColumn, outYarn);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkRowObject::SeekCellYarn( // resembles nsIMdbRowCellCursor::SeekCell()
|
||||
nsIMdbEnv* mev, // context
|
||||
mdb_pos inPos, // position of cell in row sequence
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdbYarn* outYarn) // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
// Callers can pass nil for outYarn to indicate no interest in content, so
|
||||
// only the outColumn value is returned. NOTE to subclasses: you must be
|
||||
// able to ignore outYarn when the pointer is nil; please do not crash.
|
||||
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mRowObject_Store && mRowObject_Row)
|
||||
mRowObject_Row->SeekColumn(ev, inPos, outColumn, outYarn);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end blob methods -----
|
||||
|
||||
|
||||
// } ===== end nsIMdbRow methods =====
|
||||
|
||||
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkRowObject::CloseRowObject(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
morkRow* row = mRowObject_Row;
|
||||
mRowObject_Row = 0;
|
||||
this->CloseObject(ev);
|
||||
this->MarkShut();
|
||||
|
||||
if ( row )
|
||||
{
|
||||
MORK_ASSERT(row->mRow_Object == this);
|
||||
if ( row->mRow_Object == this )
|
||||
{
|
||||
row->mRow_Object = 0; // just nil this slot -- cut ref down below
|
||||
|
||||
mRowObject_Store = 0; // morkRowObjects don't ref-cnt the owning store.
|
||||
|
||||
this->CutWeakRef(ev->AsMdbEnv()); // do last, because it might self destroy
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkRowObject::NonRowObjectTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkRowObject");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowObject::NilRowError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mRowObject_Row");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowObject::NilStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mRowObject_Store");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowObject::RowObjectRowNotSelfError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("mRowObject_Row->mRow_Object != self");
|
||||
}
|
||||
|
||||
|
||||
nsIMdbRow*
|
||||
morkRowObject::AcquireRowHandle(morkEnv* ev) // mObject_Handle
|
||||
{
|
||||
AddRef();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,232 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#define _MORKROWOBJECT_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbRow;
|
||||
#define morkDerived_kRowObject /*i*/ 0x724F /* ascii 'rO' */
|
||||
|
||||
class morkRowObject : public morkObject, public nsIMdbRow { //
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
morkRow* mRowObject_Row; // non-refcounted alias to morkRow
|
||||
morkStore* mRowObject_Store; // non-refcounted ptr to store containing row
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowObject() only if open
|
||||
virtual ~morkRowObject(); // assert that CloseRowObject() executed earlier
|
||||
|
||||
public: // morkRowObject construction & destruction
|
||||
morkRowObject(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkRow* ioRow, morkStore* ioStore);
|
||||
void CloseRowObject(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
// { ===== begin nsIMdbCollection methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetSeed(nsIMdbEnv* ev,
|
||||
mdb_seed* outSeed); // member change count
|
||||
NS_IMETHOD GetCount(nsIMdbEnv* ev,
|
||||
mdb_count* outCount); // member count
|
||||
|
||||
NS_IMETHOD GetPort(nsIMdbEnv* ev,
|
||||
nsIMdbPort** acqPort); // collection container
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
|
||||
nsIMdbCursor** acqCursor); // acquire new cursor instance
|
||||
// } ----- end cursor methods -----
|
||||
|
||||
// { ----- begin ID methods -----
|
||||
NS_IMETHOD GetOid(nsIMdbEnv* ev,
|
||||
mdbOid* outOid); // read object identity
|
||||
NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
|
||||
const mdbOid* inOid); // exchange content
|
||||
// } ----- end ID methods -----
|
||||
|
||||
// { ----- begin activity dropping methods -----
|
||||
NS_IMETHOD DropActivity( // tell collection usage no longer expected
|
||||
nsIMdbEnv* ev);
|
||||
// } ----- end activity dropping methods -----
|
||||
|
||||
// } ===== end nsIMdbCollection methods =====
|
||||
// { ===== begin nsIMdbRow methods =====
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHOD GetRowCellCursor( // make a cursor starting iteration at inRowPos
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inRowPos, // zero-based ordinal position of row in table
|
||||
nsIMdbRowCellCursor** acqCursor); // acquire new cursor instance
|
||||
// } ----- end cursor methods -----
|
||||
|
||||
// { ----- begin column methods -----
|
||||
NS_IMETHOD AddColumn( // make sure a particular column is inside row
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // column to add
|
||||
const mdbYarn* inYarn); // cell value to install
|
||||
|
||||
NS_IMETHOD CutColumn( // make sure a column is absent from the row
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn); // column to ensure absent from row
|
||||
|
||||
NS_IMETHOD CutAllColumns( // remove all columns from the row
|
||||
nsIMdbEnv* ev); // context
|
||||
// } ----- end column methods -----
|
||||
|
||||
// { ----- begin cell methods -----
|
||||
NS_IMETHOD NewCell( // get cell for specified column, or add new one
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // column to add
|
||||
nsIMdbCell** acqCell); // cell column and value
|
||||
|
||||
NS_IMETHOD AddCell( // copy a cell from another row to this row
|
||||
nsIMdbEnv* ev, // context
|
||||
const nsIMdbCell* inCell); // cell column and value
|
||||
|
||||
NS_IMETHOD GetCell( // find a cell in this row
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // column to find
|
||||
nsIMdbCell** acqCell); // cell for specified column, or null
|
||||
|
||||
NS_IMETHOD EmptyAllCells( // make all cells in row empty of content
|
||||
nsIMdbEnv* ev); // context
|
||||
// } ----- end cell methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHOD AddRow( // add all cells in another row to this one
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioSourceRow); // row to union with
|
||||
|
||||
NS_IMETHOD SetRow( // make exact duplicate of another row
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioSourceRow); // row to duplicate
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin blob methods -----
|
||||
NS_IMETHOD SetCellYarn(nsIMdbEnv* ev, // synonym for AddColumn()
|
||||
mdb_column inColumn, // column to write
|
||||
const mdbYarn* inYarn); // reads from yarn slots
|
||||
// make this text object contain content from the yarn's buffer
|
||||
|
||||
NS_IMETHOD GetCellYarn(nsIMdbEnv* ev,
|
||||
mdb_column inColumn, // column to read
|
||||
mdbYarn* outYarn); // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
|
||||
NS_IMETHOD AliasCellYarn(nsIMdbEnv* ev,
|
||||
mdb_column inColumn, // column to alias
|
||||
mdbYarn* outYarn); // writes ALL yarn slots
|
||||
|
||||
NS_IMETHOD NextCellYarn(nsIMdbEnv* ev, // iterative version of GetCellYarn()
|
||||
mdb_column* ioColumn, // next column to read
|
||||
mdbYarn* outYarn); // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
//
|
||||
// The ioColumn argument is an inout parameter which initially contains the
|
||||
// last column accessed and returns the next column corresponding to the
|
||||
// content read into the yarn. Callers should start with a zero column
|
||||
// value to say 'no previous column', which causes the first column to be
|
||||
// read. Then the value returned in ioColumn is perfect for the next call
|
||||
// to NextCellYarn(), since it will then be the previous column accessed.
|
||||
// Callers need only examine the column token returned to see which cell
|
||||
// in the row is being read into the yarn. When no more columns remain,
|
||||
// and the iteration has ended, ioColumn will return a zero token again.
|
||||
// So iterating over cells starts and ends with a zero column token.
|
||||
|
||||
NS_IMETHOD SeekCellYarn( // resembles nsIMdbRowCellCursor::SeekCell()
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inPos, // position of cell in row sequence
|
||||
mdb_column* outColumn, // column for this particular cell
|
||||
mdbYarn* outYarn); // writes some yarn slots
|
||||
// copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
|
||||
// Callers can pass nil for outYarn to indicate no interest in content, so
|
||||
// only the outColumn value is returned. NOTE to subclasses: you must be
|
||||
// able to ignore outYarn when the pointer is nil; please do not crash.
|
||||
|
||||
// } ----- end blob methods -----
|
||||
|
||||
// } ===== end nsIMdbRow methods =====
|
||||
|
||||
private: // copying is not allowed
|
||||
morkRowObject(const morkRowObject& other);
|
||||
morkRowObject& operator=(const morkRowObject& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsRowObject() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kRowObject; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonRowObjectTypeError(morkEnv* ev);
|
||||
static void NilRowError(morkEnv* ev);
|
||||
static void NilStoreError(morkEnv* ev);
|
||||
static void RowObjectRowNotSelfError(morkEnv* ev);
|
||||
|
||||
public: // other row node methods
|
||||
|
||||
nsIMdbRow* AcquireRowHandle(morkEnv* ev); // mObject_Handle
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowObject(morkRowObject* me,
|
||||
morkEnv* ev, morkRowObject** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowObject(morkRowObject* me,
|
||||
morkEnv* ev, morkRowObject** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKROWOBJECT_ */
|
|
@ -0,0 +1,666 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#include "morkRowMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#include "morkRowSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#include "morkTable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMMAP_
|
||||
#include "morkAtomMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWOBJECT_
|
||||
#include "morkRowObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkRowSpace::CloseMorkNode(morkEnv* ev) // CloseRowSpace() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseRowSpace(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkRowSpace::~morkRowSpace() // assert CloseRowSpace() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkRowSpace::morkRowSpace(morkEnv* ev,
|
||||
const morkUsage& inUsage, mork_scope inScope, morkStore* ioStore,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkSpace(ev, inUsage, inScope, ioStore, ioHeap, ioSlotHeap)
|
||||
, mRowSpace_SlotHeap( ioSlotHeap )
|
||||
, mRowSpace_Rows(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap,
|
||||
morkRowSpace_kStartRowMapSlotCount)
|
||||
, mRowSpace_Tables(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
, mRowSpace_NextTableId( 1 )
|
||||
, mRowSpace_NextRowId( 1 )
|
||||
|
||||
, mRowSpace_IndexCount( 0 )
|
||||
{
|
||||
morkAtomRowMap** cache = mRowSpace_IndexCache;
|
||||
morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
|
||||
while ( cache < cacheEnd )
|
||||
*cache++ = 0; // put nil into every slot of cache table
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
mNode_Derived = morkDerived_kRowSpace;
|
||||
|
||||
// the morkSpace base constructor handles any dirty propagation
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkRowSpace::CloseRowSpace(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
morkAtomRowMap** cache = mRowSpace_IndexCache;
|
||||
morkAtomRowMap** cacheEnd = cache + morkRowSpace_kPrimeCacheSize;
|
||||
--cache; // prepare for preincrement:
|
||||
while ( ++cache < cacheEnd )
|
||||
{
|
||||
if ( *cache )
|
||||
morkAtomRowMap::SlotStrongAtomRowMap(0, ev, cache);
|
||||
}
|
||||
|
||||
mRowSpace_Tables.CloseMorkNode(ev);
|
||||
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
this->CutAllRows(ev, &store->mStore_Pool);
|
||||
|
||||
mRowSpace_Rows.CloseMorkNode(ev);
|
||||
this->CloseSpace(ev);
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkRowSpace::NonRowSpaceTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkRowSpace");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowSpace::ZeroKindError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("zero table kind");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowSpace::ZeroScopeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("zero row scope");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowSpace::ZeroTidError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("zero table ID");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRowSpace::MinusOneRidError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("row ID is -1");
|
||||
}
|
||||
|
||||
///*static*/ void
|
||||
//morkRowSpace::ExpectAutoIdOnlyError(morkEnv* ev)
|
||||
//{
|
||||
// ev->NewError("zero row ID");
|
||||
//}
|
||||
|
||||
///*static*/ void
|
||||
//morkRowSpace::ExpectAutoIdNeverError(morkEnv* ev)
|
||||
//{
|
||||
//}
|
||||
|
||||
mork_num
|
||||
morkRowSpace::CutAllRows(morkEnv* ev, morkPool* ioPool)
|
||||
{
|
||||
if ( this->IsRowSpaceClean() )
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
mork_num outSlots = mRowSpace_Rows.MapFill();
|
||||
|
||||
#ifdef MORK_ENABLE_ZONE_ARENAS
|
||||
MORK_USED_2(ev, ioPool);
|
||||
return 0;
|
||||
#else /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
morkZone* zone = &mSpace_Store->mStore_Zone;
|
||||
morkRow* r = 0; // old key row in the map
|
||||
mork_change* c = 0;
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkRowProbeMapIter i(ev, &mRowSpace_Rows);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkRowMapIter i(ev, &mRowSpace_Rows);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
for ( c = i.FirstRow(ev, &r); c && ev->Good();
|
||||
c = i.NextRow(ev, &r) )
|
||||
{
|
||||
if ( r )
|
||||
{
|
||||
if ( r->IsRow() )
|
||||
{
|
||||
if ( r->mRow_Object )
|
||||
{
|
||||
morkRowObject::SlotWeakRowObject((morkRowObject*) 0, ev,
|
||||
&r->mRow_Object);
|
||||
}
|
||||
ioPool->ZapRow(ev, r, zone);
|
||||
}
|
||||
else
|
||||
r->NonRowTypeWarning(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
// cut nothing from the map
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
i.CutHereRow(ev, /*key*/ (morkRow**) 0);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
}
|
||||
#endif /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
|
||||
|
||||
return outSlots;
|
||||
}
|
||||
|
||||
morkTable*
|
||||
morkRowSpace::FindTableByKind(morkEnv* ev, mork_kind inTableKind)
|
||||
{
|
||||
if ( inTableKind )
|
||||
{
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
|
||||
morkTableMapIter i(ev, &mRowSpace_Tables);
|
||||
morkTable* table = i.FirstTable(ev);
|
||||
for ( ; table && ev->Good(); table = i.NextTable(ev) )
|
||||
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
mork_tid* key = 0; // nil pointer to suppress key access
|
||||
morkTable* table = 0; // old table in the map
|
||||
|
||||
mork_change* c = 0;
|
||||
morkTableMapIter i(ev, &mRowSpace_Tables);
|
||||
for ( c = i.FirstTable(ev, key, &table); c && ev->Good();
|
||||
c = i.NextTable(ev, key, &table) )
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
{
|
||||
if ( table->mTable_Kind == inTableKind )
|
||||
return table;
|
||||
}
|
||||
}
|
||||
else
|
||||
this->ZeroKindError(ev);
|
||||
|
||||
return (morkTable*) 0;
|
||||
}
|
||||
|
||||
morkTable*
|
||||
morkRowSpace::NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
||||
mork_kind inTableKind,
|
||||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
mdb_bool mustBeUnique = morkBool_kFalse;
|
||||
nsIMdbHeap* heap = store->mPort_Heap;
|
||||
morkTable* table = new(*heap, ev)
|
||||
morkTable(ev, morkUsage::kHeap, heap, store, heap, this,
|
||||
inOptionalMetaRowOid, inTid, inTableKind, mustBeUnique);
|
||||
if ( table )
|
||||
{
|
||||
if ( mRowSpace_Tables.AddTable(ev, table) )
|
||||
{
|
||||
outTable = table;
|
||||
if ( mRowSpace_NextTableId <= inTid )
|
||||
mRowSpace_NextTableId = inTid + 1;
|
||||
}
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
|
||||
}
|
||||
}
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
||||
morkTable*
|
||||
morkRowSpace::NewTable(morkEnv* ev, mork_kind inTableKind,
|
||||
mdb_bool inMustBeUnique,
|
||||
const mdbOid* inOptionalMetaRowOid) // can be nil to avoid specifying
|
||||
{
|
||||
morkTable* outTable = 0;
|
||||
morkStore* store = mSpace_Store;
|
||||
|
||||
if ( inTableKind && store )
|
||||
{
|
||||
if ( inMustBeUnique ) // need to look for existing table first?
|
||||
outTable = this->FindTableByKind(ev, inTableKind);
|
||||
|
||||
if ( !outTable && ev->Good() )
|
||||
{
|
||||
mork_tid id = this->MakeNewTableId(ev);
|
||||
if ( id )
|
||||
{
|
||||
nsIMdbHeap* heap = mSpace_Store->mPort_Heap;
|
||||
morkTable* table = new(*heap, ev)
|
||||
morkTable(ev, morkUsage::kHeap, heap, mSpace_Store, heap, this,
|
||||
inOptionalMetaRowOid, id, inTableKind, inMustBeUnique);
|
||||
if ( table )
|
||||
{
|
||||
if ( mRowSpace_Tables.AddTable(ev, table) )
|
||||
outTable = table;
|
||||
else
|
||||
table->Release();
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // morkTable does already
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( store )
|
||||
this->ZeroKindError(ev);
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
|
||||
return outTable;
|
||||
}
|
||||
|
||||
mork_tid
|
||||
morkRowSpace::MakeNewTableId(morkEnv* ev)
|
||||
{
|
||||
mork_tid outTid = 0;
|
||||
mork_tid id = mRowSpace_NextTableId;
|
||||
mork_num count = 9; // try up to eight times
|
||||
|
||||
while ( !outTid && --count ) // still trying to find an unused table ID?
|
||||
{
|
||||
if ( !mRowSpace_Tables.GetTable(ev, id) )
|
||||
outTid = id;
|
||||
else
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
mRowSpace_NextTableId = id + 1;
|
||||
return outTid;
|
||||
}
|
||||
|
||||
mork_rid
|
||||
morkRowSpace::MakeNewRowId(morkEnv* ev)
|
||||
{
|
||||
mork_rid outRid = 0;
|
||||
mork_rid id = mRowSpace_NextRowId;
|
||||
mork_num count = 9; // try up to eight times
|
||||
mdbOid oid;
|
||||
oid.mOid_Scope = this->SpaceScope();
|
||||
|
||||
while ( !outRid && --count ) // still trying to find an unused row ID?
|
||||
{
|
||||
oid.mOid_Id = id;
|
||||
if ( !mRowSpace_Rows.GetOid(ev, &oid) )
|
||||
outRid = id;
|
||||
else
|
||||
{
|
||||
MORK_ASSERT(morkBool_kFalse); // alert developer about ID problems
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
mRowSpace_NextRowId = id + 1;
|
||||
return outRid;
|
||||
}
|
||||
|
||||
morkAtomRowMap*
|
||||
morkRowSpace::make_index(morkEnv* ev, mork_column inCol)
|
||||
{
|
||||
morkAtomRowMap* outMap = 0;
|
||||
nsIMdbHeap* heap = mRowSpace_SlotHeap;
|
||||
if ( heap ) // have expected heap for allocations?
|
||||
{
|
||||
morkAtomRowMap* map = new(*heap, ev)
|
||||
morkAtomRowMap(ev, morkUsage::kHeap, heap, heap, inCol);
|
||||
|
||||
if ( map ) // able to create new map index?
|
||||
{
|
||||
if ( ev->Good() ) // no errors during construction?
|
||||
{
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkRowProbeMapIter i(ev, &mRowSpace_Rows);
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkRowMapIter i(ev, &mRowSpace_Rows);
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
mork_change* c = 0;
|
||||
morkRow* row = 0;
|
||||
mork_aid aidKey = 0;
|
||||
|
||||
for ( c = i.FirstRow(ev, &row); c && ev->Good();
|
||||
c = i.NextRow(ev, &row) ) // another row in space?
|
||||
{
|
||||
aidKey = row->GetCellAtomAid(ev, inCol);
|
||||
if ( aidKey ) // row has indexed attribute?
|
||||
map->AddAid(ev, aidKey, row); // include in map
|
||||
}
|
||||
}
|
||||
if ( ev->Good() ) // no errors constructing index?
|
||||
outMap = map; // return from function
|
||||
else
|
||||
map->CutStrongRef(ev); // discard map on error
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outMap;
|
||||
}
|
||||
|
||||
morkAtomRowMap*
|
||||
morkRowSpace::ForceMap(morkEnv* ev, mork_column inCol)
|
||||
{
|
||||
morkAtomRowMap* outMap = this->FindMap(ev, inCol);
|
||||
|
||||
if ( !outMap && ev->Good() ) // no such existing index?
|
||||
{
|
||||
if ( mRowSpace_IndexCount < morkRowSpace_kMaxIndexCount )
|
||||
{
|
||||
morkAtomRowMap* map = this->make_index(ev, inCol);
|
||||
if ( map ) // created a new index for col?
|
||||
{
|
||||
mork_count wrap = 0; // count times wrap-around occurs
|
||||
morkAtomRowMap** slot = mRowSpace_IndexCache; // table
|
||||
morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
|
||||
slot += ( inCol % morkRowSpace_kPrimeCacheSize ); // hash
|
||||
while ( *slot ) // empty slot not yet found?
|
||||
{
|
||||
if ( ++slot >= end ) // wrap around?
|
||||
{
|
||||
slot = mRowSpace_IndexCache; // back to table start
|
||||
if ( ++wrap > 1 ) // wrapped more than once?
|
||||
{
|
||||
ev->NewError("no free cache slots"); // disaster
|
||||
break; // end while loop
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( ev->Good() ) // everything went just fine?
|
||||
{
|
||||
++mRowSpace_IndexCount; // note another new map
|
||||
*slot = map; // install map in the hash table
|
||||
outMap = map; // return the new map from function
|
||||
}
|
||||
else
|
||||
map->CutStrongRef(ev); // discard map on error
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NewError("too many indexes"); // why so many indexes?
|
||||
}
|
||||
return outMap;
|
||||
}
|
||||
|
||||
morkAtomRowMap*
|
||||
morkRowSpace::FindMap(morkEnv* ev, mork_column inCol)
|
||||
{
|
||||
if ( mRowSpace_IndexCount && ev->Good() )
|
||||
{
|
||||
mork_count wrap = 0; // count times wrap-around occurs
|
||||
morkAtomRowMap** slot = mRowSpace_IndexCache; // table
|
||||
morkAtomRowMap** end = slot + morkRowSpace_kPrimeCacheSize;
|
||||
slot += ( inCol % morkRowSpace_kPrimeCacheSize ); // hash
|
||||
morkAtomRowMap* map = *slot;
|
||||
while ( map ) // another used slot to examine?
|
||||
{
|
||||
if ( inCol == map->mAtomRowMap_IndexColumn ) // found col?
|
||||
return map;
|
||||
if ( ++slot >= end ) // wrap around?
|
||||
{
|
||||
slot = mRowSpace_IndexCache;
|
||||
if ( ++wrap > 1 ) // wrapped more than once?
|
||||
return (morkAtomRowMap*) 0; // stop searching
|
||||
}
|
||||
map = *slot;
|
||||
}
|
||||
}
|
||||
return (morkAtomRowMap*) 0;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowSpace::FindRow(morkEnv* ev, mork_column inCol, const mdbYarn* inYarn)
|
||||
{
|
||||
morkRow* outRow = 0;
|
||||
|
||||
// if yarn hasn't been atomized, there can't be a corresponding row,
|
||||
// so pass in PR_FALSE to not create the row - should help history bloat
|
||||
morkAtom* atom = mSpace_Store->YarnToAtom(ev, inYarn, PR_FALSE);
|
||||
if ( atom ) // have or created an atom corresponding to input yarn?
|
||||
{
|
||||
mork_aid atomAid = atom->GetBookAtomAid();
|
||||
if ( atomAid ) // atom has an identity for use in hash table?
|
||||
{
|
||||
morkAtomRowMap* map = this->ForceMap(ev, inCol);
|
||||
if ( map ) // able to find or create index for col?
|
||||
{
|
||||
outRow = map->GetAid(ev, atomAid); // search for row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outRow;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowSpace::NewRowWithOid(morkEnv* ev, const mdbOid* inOid)
|
||||
{
|
||||
morkRow* outRow = mRowSpace_Rows.GetOid(ev, inOid);
|
||||
MORK_ASSERT(outRow==0);
|
||||
if ( !outRow && ev->Good() )
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
{
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
|
||||
if ( row )
|
||||
{
|
||||
row->InitRow(ev, inOid, this, /*length*/ 0, pool);
|
||||
|
||||
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
|
||||
{
|
||||
outRow = row;
|
||||
mork_rid rid = inOid->mOid_Id;
|
||||
if ( mRowSpace_NextRowId <= rid )
|
||||
mRowSpace_NextRowId = rid + 1;
|
||||
}
|
||||
else
|
||||
pool->ZapRow(ev, row, &store->mStore_Zone);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
}
|
||||
return outRow;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkRowSpace::NewRow(morkEnv* ev)
|
||||
{
|
||||
morkRow* outRow = 0;
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mork_rid id = this->MakeNewRowId(ev);
|
||||
if ( id )
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store )
|
||||
{
|
||||
mdbOid oid;
|
||||
oid.mOid_Scope = this->SpaceScope();
|
||||
oid.mOid_Id = id;
|
||||
morkPool* pool = this->GetSpaceStorePool();
|
||||
morkRow* row = pool->NewRow(ev, &store->mStore_Zone);
|
||||
if ( row )
|
||||
{
|
||||
row->InitRow(ev, &oid, this, /*length*/ 0, pool);
|
||||
|
||||
if ( ev->Good() && mRowSpace_Rows.AddRow(ev, row) )
|
||||
outRow = row;
|
||||
else
|
||||
pool->ZapRow(ev, row, &store->mStore_Zone);
|
||||
|
||||
if ( this->IsRowSpaceClean() && store->mStore_CanDirty )
|
||||
this->MaybeDirtyStoreAndSpace(); // InitRow() does already
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSpaceStoreError(ev);
|
||||
}
|
||||
}
|
||||
return outRow;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
morkRowSpaceMap::~morkRowSpaceMap()
|
||||
{
|
||||
}
|
||||
|
||||
morkRowSpaceMap::morkRowSpaceMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkNodeMap(ev, inUsage, ioHeap, ioSlotHeap)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kRowSpaceMap;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,265 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#define _MORKROWSPACE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#include "morkRowMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#include "morkTable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKARRAY_
|
||||
#include "morkArray.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowSpace /*i*/ 0x7253 /* ascii 'rS' */
|
||||
|
||||
#define morkRowSpace_kStartRowMapSlotCount 11
|
||||
|
||||
#define morkRowSpace_kMaxIndexCount 8 /* no more indexes than this */
|
||||
#define morkRowSpace_kPrimeCacheSize 17 /* should be prime number */
|
||||
|
||||
class morkAtomRowMap;
|
||||
|
||||
/*| morkRowSpace:
|
||||
|*/
|
||||
class morkRowSpace : public morkSpace { //
|
||||
|
||||
// public: // slots inherited from morkSpace (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkStore* mSpace_Store; // weak ref to containing store
|
||||
|
||||
// mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
|
||||
// mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
|
||||
// mork_u1 mSpace_Pad[ 2 ]; // pad to u4 alignment
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
nsIMdbHeap* mRowSpace_SlotHeap;
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkRowProbeMap mRowSpace_Rows; // hash table of morkRow instances
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkRowMap mRowSpace_Rows; // hash table of morkRow instances
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkTableMap mRowSpace_Tables; // all the tables in this row scope
|
||||
|
||||
mork_tid mRowSpace_NextTableId; // for auto-assigning table IDs
|
||||
mork_rid mRowSpace_NextRowId; // for auto-assigning row IDs
|
||||
|
||||
mork_count mRowSpace_IndexCount; // if nonzero, row indexes exist
|
||||
|
||||
// every nonzero slot in IndexCache is a strong ref to a morkAtomRowMap:
|
||||
morkAtomRowMap* mRowSpace_IndexCache[ morkRowSpace_kPrimeCacheSize ];
|
||||
|
||||
morkDeque mRowSpace_TablesByPriority[ morkPriority_kCount ];
|
||||
|
||||
public: // more specific dirty methods for row space:
|
||||
void SetRowSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetRowSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsRowSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsRowSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseRowSpace() only if open
|
||||
virtual ~morkRowSpace(); // assert that CloseRowSpace() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkRowSpace(morkEnv* ev, const morkUsage& inUsage, mork_scope inScope,
|
||||
morkStore* ioStore, nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseRowSpace(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsRowSpace() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kRowSpace; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonRowSpaceTypeError(morkEnv* ev);
|
||||
static void ZeroScopeError(morkEnv* ev);
|
||||
static void ZeroKindError(morkEnv* ev);
|
||||
static void ZeroTidError(morkEnv* ev);
|
||||
static void MinusOneRidError(morkEnv* ev);
|
||||
|
||||
//static void ExpectAutoIdOnlyError(morkEnv* ev);
|
||||
//static void ExpectAutoIdNeverError(morkEnv* ev);
|
||||
|
||||
public: // other space methods
|
||||
|
||||
mork_num CutAllRows(morkEnv* ev, morkPool* ioPool);
|
||||
// CutAllRows() puts all rows and cells back into the pool.
|
||||
|
||||
morkTable* NewTable(morkEnv* ev, mork_kind inTableKind,
|
||||
mdb_bool inMustBeUnique, const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
morkTable* NewTableWithTid(morkEnv* ev, mork_tid inTid,
|
||||
mork_kind inTableKind, const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
morkTable* FindTableByKind(morkEnv* ev, mork_kind inTableKind);
|
||||
morkTable* FindTableByTid(morkEnv* ev, mork_tid inTid)
|
||||
{ return mRowSpace_Tables.GetTable(ev, inTid); }
|
||||
|
||||
mork_tid MakeNewTableId(morkEnv* ev);
|
||||
mork_rid MakeNewRowId(morkEnv* ev);
|
||||
|
||||
// morkRow* FindRowByRid(morkEnv* ev, mork_rid inRid)
|
||||
// { return (morkRow*) mRowSpace_Rows.GetRow(ev, inRid); }
|
||||
|
||||
morkRow* NewRowWithOid(morkEnv* ev, const mdbOid* inOid);
|
||||
morkRow* NewRow(morkEnv* ev);
|
||||
|
||||
morkRow* FindRow(morkEnv* ev, mork_column inColumn, const mdbYarn* inYarn);
|
||||
|
||||
morkAtomRowMap* ForceMap(morkEnv* ev, mork_column inColumn);
|
||||
morkAtomRowMap* FindMap(morkEnv* ev, mork_column inColumn);
|
||||
|
||||
protected: // internal utilities
|
||||
morkAtomRowMap* make_index(morkEnv* ev, mork_column inColumn);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakRowSpace(morkRowSpace* me,
|
||||
morkEnv* ev, morkRowSpace** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongRowSpace(morkRowSpace* me,
|
||||
morkEnv* ev, morkRowSpace** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kRowSpaceMap /*i*/ 0x725A /* ascii 'rZ' */
|
||||
|
||||
/*| morkRowSpaceMap: maps mork_scope -> morkRowSpace
|
||||
|*/
|
||||
class morkRowSpaceMap : public morkNodeMap { // for mapping tokens to tables
|
||||
|
||||
public:
|
||||
|
||||
virtual ~morkRowSpaceMap();
|
||||
morkRowSpaceMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
|
||||
public: // other map methods
|
||||
|
||||
mork_bool AddRowSpace(morkEnv* ev, morkRowSpace* ioRowSpace)
|
||||
{ return this->AddNode(ev, ioRowSpace->SpaceScope(), ioRowSpace); }
|
||||
// the AddRowSpace() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutRowSpace(morkEnv* ev, mork_scope inScope)
|
||||
{ return this->CutNode(ev, inScope); }
|
||||
// The CutRowSpace() boolean return indicates whether removal happened.
|
||||
|
||||
morkRowSpace* GetRowSpace(morkEnv* ev, mork_scope inScope)
|
||||
{ return (morkRowSpace*) this->GetNode(ev, inScope); }
|
||||
// Note the returned space does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllRowSpaces(morkEnv* ev)
|
||||
{ return this->CutAllNodes(ev); }
|
||||
// CutAllRowSpaces() releases all the referenced table values.
|
||||
};
|
||||
|
||||
class morkRowSpaceMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
|
||||
public:
|
||||
morkRowSpaceMapIter(morkEnv* ev, morkRowSpaceMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkRowSpaceMapIter( ) : morkMapIter() { }
|
||||
void InitRowSpaceMapIter(morkEnv* ev, morkRowSpaceMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change*
|
||||
FirstRowSpace(morkEnv* ev, mork_scope* outScope, morkRowSpace** outRowSpace)
|
||||
{ return this->First(ev, outScope, outRowSpace); }
|
||||
|
||||
mork_change*
|
||||
NextRowSpace(morkEnv* ev, mork_scope* outScope, morkRowSpace** outRowSpace)
|
||||
{ return this->Next(ev, outScope, outRowSpace); }
|
||||
|
||||
mork_change*
|
||||
HereRowSpace(morkEnv* ev, mork_scope* outScope, morkRowSpace** outRowSpace)
|
||||
{ return this->Here(ev, outScope, outRowSpace); }
|
||||
|
||||
mork_change*
|
||||
CutHereRowSpace(morkEnv* ev, mork_scope* outScope, morkRowSpace** outRowSpace)
|
||||
{ return this->CutHere(ev, outScope, outRowSpace); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKROWSPACE_ */
|
|
@ -0,0 +1,206 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSEARCHROWCURSOR_
|
||||
#include "morkSearchRowCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKUNIQROWCURSOR_
|
||||
#include "morkUniqRowCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#include "morkTable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkSearchRowCursor::CloseMorkNode(morkEnv* ev) // CloseSearchRowCursor() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseSearchRowCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkSearchRowCursor::~morkSearchRowCursor() // CloseSearchRowCursor() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkSearchRowCursor::morkSearchRowCursor(morkEnv* ev,
|
||||
const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos)
|
||||
: morkTableRowCursor(ev, inUsage, ioHeap, ioTable, inRowPos)
|
||||
// , mSortingRowCursor_Sorting( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioTable )
|
||||
{
|
||||
// morkSorting::SlotWeakSorting(ioSorting, ev, &mSortingRowCursor_Sorting);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
// mNode_Derived = morkDerived_kTableRowCursor;
|
||||
// mNode_Derived must stay equal to kTableRowCursor
|
||||
}
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkSearchRowCursor::CloseSearchRowCursor(morkEnv* ev)
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
// morkSorting::SlotWeakSorting((morkSorting*) 0, ev, &mSortingRowCursor_Sorting);
|
||||
this->CloseTableRowCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkSearchRowCursor::NonSearchRowCursorTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkSearchRowCursor");
|
||||
}
|
||||
|
||||
morkUniqRowCursor*
|
||||
morkSearchRowCursor::MakeUniqCursor(morkEnv* ev)
|
||||
{
|
||||
morkUniqRowCursor* outCursor = 0;
|
||||
|
||||
return outCursor;
|
||||
}
|
||||
|
||||
#if 0
|
||||
orkinTableRowCursor*
|
||||
morkSearchRowCursor::AcquireUniqueRowCursorHandle(morkEnv* ev)
|
||||
{
|
||||
orkinTableRowCursor* outCursor = 0;
|
||||
|
||||
morkUniqRowCursor* uniqCursor = this->MakeUniqCursor(ev);
|
||||
if ( uniqCursor )
|
||||
{
|
||||
outCursor = uniqCursor->AcquireTableRowCursorHandle(ev);
|
||||
uniqCursor->CutStrongRef(ev);
|
||||
}
|
||||
return outCursor;
|
||||
}
|
||||
#endif
|
||||
mork_bool
|
||||
morkSearchRowCursor::CanHaveDupRowMembers(morkEnv* ev)
|
||||
{
|
||||
return morkBool_kTrue; // true is correct
|
||||
}
|
||||
|
||||
mork_count
|
||||
morkSearchRowCursor::GetMemberCount(morkEnv* ev)
|
||||
{
|
||||
morkTable* table = mTableRowCursor_Table;
|
||||
if ( table )
|
||||
return table->mTable_RowArray.mArray_Fill;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkSearchRowCursor::NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos)
|
||||
{
|
||||
morkRow* outRow = 0;
|
||||
mork_pos pos = -1;
|
||||
|
||||
morkTable* table = mTableRowCursor_Table;
|
||||
if ( table )
|
||||
{
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
*outPos = pos;
|
||||
return outRow;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,137 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKSEARCHROWCURSOR_
|
||||
#define _MORKSEARCHROWCURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLEROWCURSOR_
|
||||
#include "morkTableRowCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class morkUniqRowCursor;
|
||||
class orkinTableRowCursor;
|
||||
// #define morkDerived_kSearchRowCursor /*i*/ 0x7352 /* ascii 'sR' */
|
||||
|
||||
class morkSearchRowCursor : public morkTableRowCursor { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkFactory* mObject_Factory; // weak ref to suite factory
|
||||
|
||||
// mork_seed mCursor_Seed;
|
||||
// mork_pos mCursor_Pos;
|
||||
// mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
// mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
// morkTable* mTableRowCursor_Table; // weak ref to table
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseSearchRowCursor()
|
||||
virtual ~morkSearchRowCursor(); // assert that close executed earlier
|
||||
|
||||
public: // morkSearchRowCursor construction & destruction
|
||||
morkSearchRowCursor(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos);
|
||||
void CloseSearchRowCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkSearchRowCursor(const morkSearchRowCursor& other);
|
||||
morkSearchRowCursor& operator=(const morkSearchRowCursor& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
// mork_bool IsSearchRowCursor() const
|
||||
// { return IsNode() && mNode_Derived == morkDerived_kSearchRowCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonSearchRowCursorTypeError(morkEnv* ev);
|
||||
|
||||
public: // uniquify
|
||||
|
||||
morkUniqRowCursor* MakeUniqCursor(morkEnv* ev);
|
||||
|
||||
public: // other search row cursor methods
|
||||
|
||||
virtual mork_bool CanHaveDupRowMembers(morkEnv* ev);
|
||||
virtual mork_count GetMemberCount(morkEnv* ev);
|
||||
|
||||
#if 0
|
||||
virtual orkinTableRowCursor* AcquireUniqueRowCursorHandle(morkEnv* ev);
|
||||
#endif
|
||||
|
||||
// virtual mdb_pos NextRowOid(morkEnv* ev, mdbOid* outOid);
|
||||
virtual morkRow* NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakSearchRowCursor(morkSearchRowCursor* me,
|
||||
morkEnv* ev, morkSearchRowCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongSearchRowCursor(morkSearchRowCursor* me,
|
||||
morkEnv* ev, morkSearchRowCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKSEARCHROWCURSOR_ */
|
|
@ -0,0 +1,324 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSINK_
|
||||
#include "morkSink.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*virtual*/ morkSink::~morkSink()
|
||||
{
|
||||
mSink_At = 0;
|
||||
mSink_End = 0;
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkSpool::FlushSink(morkEnv* ev) // sync mSpool_Coil->mBuf_Fill
|
||||
{
|
||||
morkCoil* coil = mSpool_Coil;
|
||||
if ( coil )
|
||||
{
|
||||
mork_u1* body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body )
|
||||
{
|
||||
mork_u1* at = mSink_At;
|
||||
mork_u1* end = mSink_End;
|
||||
if ( at >= body && at <= end ) // expected cursor order?
|
||||
{
|
||||
mork_fill fill = (mork_fill) (at - body); // current content size
|
||||
if ( fill <= coil->mBlob_Size )
|
||||
coil->mBuf_Fill = fill;
|
||||
else
|
||||
{
|
||||
coil->BlobFillOverSizeError(ev);
|
||||
coil->mBuf_Fill = coil->mBlob_Size; // make it safe
|
||||
}
|
||||
}
|
||||
else
|
||||
this->BadSpoolCursorOrderError(ev);
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSpoolCoilError(ev);
|
||||
}
|
||||
|
||||
/*virtual*/ void
|
||||
morkSpool::SpillPutc(morkEnv* ev, int c) // grow coil and write byte
|
||||
{
|
||||
morkCoil* coil = mSpool_Coil;
|
||||
if ( coil )
|
||||
{
|
||||
mork_u1* body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body )
|
||||
{
|
||||
mork_u1* at = mSink_At;
|
||||
mork_u1* end = mSink_End;
|
||||
if ( at >= body && at <= end ) // expected cursor order?
|
||||
{
|
||||
mork_size size = coil->mBlob_Size;
|
||||
mork_fill fill = (mork_fill) (at - body); // current content size
|
||||
if ( fill <= size ) // less content than medium size?
|
||||
{
|
||||
coil->mBuf_Fill = fill;
|
||||
if ( at >= end ) // need to grow the coil?
|
||||
{
|
||||
if ( size > 2048 ) // grow slower over 2K?
|
||||
size += 512;
|
||||
else
|
||||
{
|
||||
mork_size growth = ( size * 4 ) / 3; // grow by 33%
|
||||
if ( growth < 64 ) // grow faster under (64 * 3)?
|
||||
growth = 64;
|
||||
size += growth;
|
||||
}
|
||||
if ( coil->GrowCoil(ev, size) ) // made coil bigger?
|
||||
{
|
||||
body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body ) // have a coil body?
|
||||
{
|
||||
mSink_At = at = body + fill;
|
||||
mSink_End = end = body + coil->mBlob_Size;
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
}
|
||||
if ( ev->Good() ) // seem ready to write byte c?
|
||||
{
|
||||
if ( at < end ) // morkSink::Putc() would succeed?
|
||||
{
|
||||
*at++ = (mork_u1) c;
|
||||
mSink_At = at;
|
||||
coil->mBuf_Fill = fill + 1;
|
||||
}
|
||||
else
|
||||
this->BadSpoolCursorOrderError(ev);
|
||||
}
|
||||
}
|
||||
else // fill exceeds size
|
||||
{
|
||||
coil->BlobFillOverSizeError(ev);
|
||||
coil->mBuf_Fill = coil->mBlob_Size; // make it safe
|
||||
}
|
||||
}
|
||||
else
|
||||
this->BadSpoolCursorOrderError(ev);
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSpoolCoilError(ev);
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
// public: // public non-poly morkSink methods
|
||||
|
||||
/*virtual*/
|
||||
morkSpool::~morkSpool()
|
||||
// Zero all slots to show this sink is disabled, but destroy no memory.
|
||||
// Note it is typically unnecessary to flush this coil sink, since all
|
||||
// content is written directly to the coil without any buffering.
|
||||
{
|
||||
mSink_At = 0;
|
||||
mSink_End = 0;
|
||||
mSpool_Coil = 0;
|
||||
}
|
||||
|
||||
morkSpool::morkSpool(morkEnv* ev, morkCoil* ioCoil)
|
||||
// After installing the coil, calls Seek(ev, 0) to prepare for writing.
|
||||
: morkSink()
|
||||
, mSpool_Coil( 0 )
|
||||
{
|
||||
mSink_At = 0; // set correctly later in Seek()
|
||||
mSink_End = 0; // set correctly later in Seek()
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioCoil )
|
||||
{
|
||||
mSpool_Coil = ioCoil;
|
||||
this->Seek(ev, /*pos*/ 0);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
// ----- All boolean return values below are equal to ev->Good(): -----
|
||||
|
||||
/*static*/ void
|
||||
morkSpool::BadSpoolCursorOrderError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad morkSpool cursor order");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkSpool::NilSpoolCoilError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mSpool_Coil");
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkSpool::Seek(morkEnv* ev, mork_pos inPos)
|
||||
// Changed the current write position in coil's buffer to inPos.
|
||||
// For example, to start writing the coil from scratch, use inPos==0.
|
||||
{
|
||||
morkCoil* coil = mSpool_Coil;
|
||||
if ( coil )
|
||||
{
|
||||
mork_size minSize = (mork_size) (inPos + 64);
|
||||
|
||||
if ( coil->mBlob_Size < minSize )
|
||||
coil->GrowCoil(ev, minSize);
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
coil->mBuf_Fill = (mork_fill) inPos;
|
||||
mork_u1* body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body )
|
||||
{
|
||||
mSink_At = body + inPos;
|
||||
mSink_End = body + coil->mBlob_Size;
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
this->NilSpoolCoilError(ev);
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkSpool::Write(morkEnv* ev, const void* inBuf, mork_size inSize)
|
||||
// write inSize bytes of inBuf to current position inside coil's buffer
|
||||
{
|
||||
// This method is conceptually very similar to morkStream::Write(),
|
||||
// and this code was written while looking at that method for clues.
|
||||
|
||||
morkCoil* coil = mSpool_Coil;
|
||||
if ( coil )
|
||||
{
|
||||
mork_u1* body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body )
|
||||
{
|
||||
if ( inBuf && inSize ) // anything to write?
|
||||
{
|
||||
mork_u1* at = mSink_At;
|
||||
mork_u1* end = mSink_End;
|
||||
if ( at >= body && at <= end ) // expected cursor order?
|
||||
{
|
||||
// note coil->mBuf_Fill can be stale after morkSink::Putc():
|
||||
mork_pos fill = at - body; // current content size
|
||||
mork_num space = (mork_num) (end - at); // space left in body
|
||||
if ( space < inSize ) // not enough to hold write?
|
||||
{
|
||||
mork_size minGrowth = space + 16;
|
||||
mork_size minSize = coil->mBlob_Size + minGrowth;
|
||||
if ( coil->GrowCoil(ev, minSize) )
|
||||
{
|
||||
body = (mork_u1*) coil->mBuf_Body;
|
||||
if ( body )
|
||||
{
|
||||
mSink_At = at = body + fill;
|
||||
mSink_End = end = body + coil->mBlob_Size;
|
||||
space = (mork_num) (end - at); // space left in body
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
}
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( space >= inSize ) // enough room to hold write?
|
||||
{
|
||||
MORK_MEMCPY(at, inBuf, inSize); // into body
|
||||
mSink_At = at + inSize; // advance past written bytes
|
||||
coil->mBuf_Fill = fill + inSize; // "flush" to fix fill
|
||||
}
|
||||
else
|
||||
ev->NewError("insufficient morkSpool space");
|
||||
}
|
||||
}
|
||||
else
|
||||
this->BadSpoolCursorOrderError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
coil->NilBufBodyError(ev);
|
||||
}
|
||||
else
|
||||
this->NilSpoolCoilError(ev);
|
||||
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkSpool::PutString(morkEnv* ev, const char* inString)
|
||||
// call Write() with inBuf=inString and inSize=strlen(inString),
|
||||
// unless inString is null, in which case we then do nothing at all.
|
||||
{
|
||||
if ( inString )
|
||||
{
|
||||
mork_size size = MORK_STRLEN(inString);
|
||||
this->Write(ev, inString, size);
|
||||
}
|
||||
return ev->Good();
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,193 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKSINK_
|
||||
#define _MORKSINK_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBLOB_
|
||||
#include "morkBlob.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| morkSink is intended to be a very cheap buffered i/o sink which
|
||||
**| writes to bufs and other strings a single byte at a time. The
|
||||
**| basic idea is that writing a single byte has a very cheap average
|
||||
**| cost, because a polymophic function call need only occur when the
|
||||
**| space between At and End is exhausted. The rest of the time a
|
||||
**| very cheap inline method will write a byte, and then bump a pointer.
|
||||
**|
|
||||
**|| At: the current position in some sequence of bytes at which to
|
||||
**| write the next byte put into the sink. Presumably At points into
|
||||
**| the private storage of some space which is not yet filled (except
|
||||
**| when At reaches End, and the overflow must then spill). Note both
|
||||
**| At and End are zeroed in the destructor to help show that a sink
|
||||
**| is no longer usable; this is safe because At==End causes the case
|
||||
**| where SpillPutc() is called to handled an exhausted buffer space.
|
||||
**|
|
||||
**|| End: an address one byte past the last byte which can be written
|
||||
**| without needing to make a buffer larger than previously. When At
|
||||
**| and End are equal, this means there is no space to write a byte,
|
||||
**| and that some underlying buffer space must be grown before another
|
||||
**| byte can be written. Note At must always be less than or equal to
|
||||
**| End, and otherwise an important invariant has failed severely.
|
||||
**|
|
||||
**|| Buf: this original class slot has been commented out in the new
|
||||
**| and more abstract version of this sink class, but the general idea
|
||||
**| behind this slot should be explained to help design subclasses.
|
||||
**| Each subclass should provide space into which At and End can point,
|
||||
**| where End is beyond the last writable byte, and At is less than or
|
||||
**| equal to this point inside the same buffer. With some kinds of
|
||||
**| medium, such as writing to an instance of morkBlob, it is feasible
|
||||
**| to point directly into the final resting place for all the content
|
||||
**| written to the medium. Other mediums such as files, which write
|
||||
**| only through function calls, will typically need a local buffer
|
||||
**| to efficiently accumulate many bytes between such function calls.
|
||||
**|
|
||||
**|| FlushSink: this flush method should move any buffered content to
|
||||
**| its final destination. For example, for buffered writes to a
|
||||
**| string medium, where string methods are function calls and not just
|
||||
**| inline macros, it is faster to accumulate many bytes in a small
|
||||
**| local buffer and then move these en masse later in a single call.
|
||||
**|
|
||||
**|| SpillPutc: when At is greater than or equal to End, this means an
|
||||
**| underlying buffer has become full, so the buffer must be flushed
|
||||
**| before a new byte can be written. The intention is that SpillPutc()
|
||||
**| will be equivalent to calling FlushSink() followed by another call
|
||||
**| to Putc(), where the flush is expected to make At less then End once
|
||||
**| again. Except that FlushSink() need not make the underlying buffer
|
||||
**| any larger, and SpillPutc() typically must make room for more bytes.
|
||||
**| Note subclasses might want to guard against the case that both At
|
||||
**| and End are null, which happens when a sink is destroyed, which sets
|
||||
**| both these pointers to null as an indication the sink is disabled.
|
||||
|*/
|
||||
class morkSink {
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public sink virtual methods
|
||||
|
||||
virtual void FlushSink(morkEnv* ev) = 0;
|
||||
virtual void SpillPutc(morkEnv* ev, int c) = 0;
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // member variables
|
||||
|
||||
mork_u1* mSink_At; // pointer into mSink_Buf
|
||||
mork_u1* mSink_End; // one byte past last content byte
|
||||
|
||||
// define morkSink_kBufSize 256 /* small enough to go on stack */
|
||||
|
||||
// mork_u1 mSink_Buf[ morkSink_kBufSize + 4 ];
|
||||
// want plus one for any needed end null byte; use plus 4 for alignment
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkSink methods
|
||||
|
||||
virtual ~morkSink(); // zero both At and End; virtual for subclasses
|
||||
morkSink() { } // does nothing; subclasses must set At and End suitably
|
||||
|
||||
void Putc(morkEnv* ev, int c)
|
||||
{
|
||||
if ( mSink_At < mSink_End )
|
||||
*mSink_At++ = (mork_u1) c;
|
||||
else
|
||||
this->SpillPutc(ev, c);
|
||||
}
|
||||
};
|
||||
|
||||
/*| morkSpool: an output sink that efficiently writes individual bytes
|
||||
**| or entire byte sequences to a coil instance, which grows as needed by
|
||||
**| using the heap instance in the coil to grow the internal buffer.
|
||||
**|
|
||||
**|| Note we do not "own" the coil referenced by mSpool_Coil, and
|
||||
**| the lifetime of the coil is expected to equal or exceed that of this
|
||||
**| sink by some external means. Typical usage might involve keeping an
|
||||
**| instance of morkCoil and an instance of morkSpool in the same
|
||||
**| owning parent object, which uses the spool with the associated coil.
|
||||
|*/
|
||||
class morkSpool : public morkSink { // for buffered i/o to a morkCoil
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public sink virtual methods
|
||||
|
||||
// when morkSink::Putc() moves mSink_At, mSpool_Coil->mBuf_Fill is wrong:
|
||||
|
||||
virtual void FlushSink(morkEnv* ev); // sync mSpool_Coil->mBuf_Fill
|
||||
virtual void SpillPutc(morkEnv* ev, int c); // grow coil and write byte
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // member variables
|
||||
morkCoil* mSpool_Coil; // destination medium for written bytes
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkSink methods
|
||||
|
||||
static void BadSpoolCursorOrderError(morkEnv* ev);
|
||||
static void NilSpoolCoilError(morkEnv* ev);
|
||||
|
||||
virtual ~morkSpool();
|
||||
// Zero all slots to show this sink is disabled, but destroy no memory.
|
||||
// Note it is typically unnecessary to flush this coil sink, since all
|
||||
// content is written directly to the coil without any buffering.
|
||||
|
||||
morkSpool(morkEnv* ev, morkCoil* ioCoil);
|
||||
// After installing the coil, calls Seek(ev, 0) to prepare for writing.
|
||||
|
||||
// ----- All boolean return values below are equal to ev->Good(): -----
|
||||
|
||||
mork_bool Seek(morkEnv* ev, mork_pos inPos);
|
||||
// Changed the current write position in coil's buffer to inPos.
|
||||
// For example, to start writing the coil from scratch, use inPos==0.
|
||||
|
||||
mork_bool Write(morkEnv* ev, const void* inBuf, mork_size inSize);
|
||||
// write inSize bytes of inBuf to current position inside coil's buffer
|
||||
|
||||
mork_bool PutBuf(morkEnv* ev, const morkBuf& inBuffer)
|
||||
{ return this->Write(ev, inBuffer.mBuf_Body, inBuffer.mBuf_Fill); }
|
||||
|
||||
mork_bool PutString(morkEnv* ev, const char* inString);
|
||||
// call Write() with inBuf=inString and inSize=strlen(inString),
|
||||
// unless inString is null, in which case we then do nothing at all.
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKSINK_ */
|
|
@ -0,0 +1,189 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#include "morkSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkSpace::CloseMorkNode(morkEnv* ev) // CloseSpace() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseSpace(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkSpace::~morkSpace() // assert CloseSpace() executed earlier
|
||||
{
|
||||
MORK_ASSERT(SpaceScope()==0);
|
||||
MORK_ASSERT(mSpace_Store==0);
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
//morkSpace::morkSpace(morkEnv* ev, const morkUsage& inUsage,
|
||||
// nsIMdbHeap* ioNodeHeap, const morkMapForm& inForm,
|
||||
// nsIMdbHeap* ioSlotHeap)
|
||||
//: morkNode(ev, inUsage, ioNodeHeap)
|
||||
//, mSpace_Map(ev, morkUsage::kMember, (nsIMdbHeap*) 0, ioSlotHeap)
|
||||
//{
|
||||
// ev->StubMethodOnlyError();
|
||||
//}
|
||||
|
||||
/*public non-poly*/
|
||||
morkSpace::morkSpace(morkEnv* ev,
|
||||
const morkUsage& inUsage, mork_scope inScope, morkStore* ioStore,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap)
|
||||
: morkBead(ev, inUsage, ioHeap, inScope)
|
||||
, mSpace_Store( 0 )
|
||||
, mSpace_DoAutoIDs( morkBool_kFalse )
|
||||
, mSpace_HaveDoneAutoIDs( morkBool_kFalse )
|
||||
, mSpace_CanDirty( morkBool_kFalse ) // only when store can be dirtied
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioStore && ioSlotHeap )
|
||||
{
|
||||
morkStore::SlotWeakStore(ioStore, ev, &mSpace_Store);
|
||||
|
||||
mSpace_CanDirty = ioStore->mStore_CanDirty;
|
||||
if ( mSpace_CanDirty ) // this new space dirties the store?
|
||||
this->MaybeDirtyStoreAndSpace();
|
||||
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kSpace;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkSpace::CloseSpace(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
morkStore::SlotWeakStore((morkStore*) 0, ev, &mSpace_Store);
|
||||
mBead_Color = 0; // this->CloseBead();
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkSpace::NonAsciiSpaceScopeName(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("SpaceScope() > 0x7F");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkSpace::NilSpaceStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mSpace_Store");
|
||||
}
|
||||
|
||||
morkPool* morkSpace::GetSpaceStorePool() const
|
||||
{
|
||||
return &mSpace_Store->mStore_Pool;
|
||||
}
|
||||
|
||||
mork_bool morkSpace::MaybeDirtyStoreAndSpace()
|
||||
{
|
||||
morkStore* store = mSpace_Store;
|
||||
if ( store && store->mStore_CanDirty )
|
||||
{
|
||||
store->SetStoreDirty();
|
||||
mSpace_CanDirty = morkBool_kTrue;
|
||||
}
|
||||
|
||||
if ( mSpace_CanDirty )
|
||||
{
|
||||
this->SetSpaceDirty();
|
||||
return morkBool_kTrue;
|
||||
}
|
||||
|
||||
return morkBool_kFalse;
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,142 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKSPACE_
|
||||
#define _MORKSPACE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#include "morkBead.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkSpace_kInitialSpaceSlots /*i*/ 1024 /* default */
|
||||
#define morkDerived_kSpace /*i*/ 0x5370 /* ascii 'Sp' */
|
||||
|
||||
/*| morkSpace:
|
||||
|*/
|
||||
class morkSpace : public morkBead { //
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
|
||||
public: // bead color setter & getter replace obsolete member mTable_Id:
|
||||
|
||||
mork_tid SpaceScope() const { return mBead_Color; }
|
||||
void SetSpaceScope(mork_scope inScope) { mBead_Color = inScope; }
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkStore* mSpace_Store; // weak ref to containing store
|
||||
|
||||
mork_bool mSpace_DoAutoIDs; // whether db should assign member IDs
|
||||
mork_bool mSpace_HaveDoneAutoIDs; // whether actually auto assigned IDs
|
||||
mork_bool mSpace_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mSpace_Pad; // pad to u4 alignment
|
||||
|
||||
public: // more specific dirty methods for space:
|
||||
void SetSpaceDirty() { this->SetNodeDirty(); }
|
||||
void SetSpaceClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsSpaceClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsSpaceDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseSpace() only if open
|
||||
virtual ~morkSpace(); // assert that CloseSpace() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
//morkSpace(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap,
|
||||
// const morkMapForm& inForm, nsIMdbHeap* ioSlotHeap);
|
||||
|
||||
morkSpace(morkEnv* ev, const morkUsage& inUsage,mork_scope inScope,
|
||||
morkStore* ioStore, nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioSlotHeap);
|
||||
void CloseSpace(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsSpace() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kSpace; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // other space methods
|
||||
|
||||
mork_bool MaybeDirtyStoreAndSpace();
|
||||
|
||||
static void NonAsciiSpaceScopeName(morkEnv* ev);
|
||||
static void NilSpaceStoreError(morkEnv* ev);
|
||||
|
||||
morkPool* GetSpaceStorePool() const;
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakSpace(morkSpace* me,
|
||||
morkEnv* ev, morkSpace** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongSpace(morkSpace* me,
|
||||
morkEnv* ev, morkSpace** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKSPACE_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,794 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#define _MORKSTORE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPOOL_
|
||||
#include "morkPool.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#include "morkZone.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOM_
|
||||
#include "morkAtom.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#include "morkRowSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMSPACE_
|
||||
#include "morkAtomSpace.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kPort /*i*/ 0x7054 /* ascii 'pT' */
|
||||
|
||||
#define morkDerived_kStore /*i*/ 0x7354 /* ascii 'sT' */
|
||||
|
||||
/*| kGroundColumnSpace: we use the 'column space' as the default scope
|
||||
**| for grounding column name IDs, and this is also the default scope for
|
||||
**| all other explicitly tokenized strings.
|
||||
|*/
|
||||
#define morkStore_kGroundColumnSpace 'c' /* for mStore_GroundColumnSpace*/
|
||||
#define morkStore_kColumnSpaceScope ((mork_scope) 'c') /*kGroundColumnSpace*/
|
||||
#define morkStore_kValueSpaceScope ((mork_scope) 'v')
|
||||
#define morkStore_kStreamBufSize (8 * 1024) /* okay buffer size */
|
||||
|
||||
#define morkStore_kReservedColumnCount 0x20 /* for well-known columns */
|
||||
|
||||
#define morkStore_kNoneToken ((mork_token) 'n')
|
||||
#define morkStore_kFormColumn ((mork_column) 'f')
|
||||
#define morkStore_kAtomScopeColumn ((mork_column) 'a')
|
||||
#define morkStore_kRowScopeColumn ((mork_column) 'r')
|
||||
#define morkStore_kMetaScope ((mork_scope) 'm')
|
||||
#define morkStore_kKindColumn ((mork_column) 'k')
|
||||
#define morkStore_kStatusColumn ((mork_column) 's')
|
||||
|
||||
/*| morkStore:
|
||||
|*/
|
||||
class morkStore : public morkObject, public nsIMdbStore {
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
morkEnv* mPort_Env; // non-refcounted env which created port
|
||||
morkFactory* mPort_Factory; // weak ref to suite factory
|
||||
nsIMdbHeap* mPort_Heap; // heap in which this port allocs objects
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
|
||||
void ClosePort(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsPort() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kPort; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // other port methods
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
// NS_IMETHOD IsFrozenMdbObject(nsIMdbEnv* ev, mdb_bool* outIsReadonly);
|
||||
// same as nsIMdbPort::GetIsPortReadonly() when this object is inside a port.
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin factory methods -----
|
||||
// NS_IMETHOD GetMdbFactory(nsIMdbEnv* ev, nsIMdbFactory** acqFactory);
|
||||
// } ----- end factory methods -----
|
||||
|
||||
// { ----- begin ref counting for well-behaved cyclic graphs -----
|
||||
NS_IMETHOD GetWeakRefCount(nsIMdbEnv* ev, // weak refs
|
||||
mdb_count* outCount);
|
||||
NS_IMETHOD GetStrongRefCount(nsIMdbEnv* ev, // strong refs
|
||||
mdb_count* outCount);
|
||||
|
||||
NS_IMETHOD AddWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD AddStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CutWeakRef(nsIMdbEnv* ev);
|
||||
NS_IMETHOD CutStrongRef(nsIMdbEnv* ev);
|
||||
|
||||
NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev); // called at strong refs zero
|
||||
NS_IMETHOD IsOpenMdbObject(nsIMdbEnv* ev, mdb_bool* outOpen);
|
||||
// } ----- end ref counting -----
|
||||
|
||||
// } ===== end nsIMdbObject methods =====
|
||||
|
||||
// { ===== begin nsIMdbPort methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetIsPortReadonly(nsIMdbEnv* ev, mdb_bool* outBool);
|
||||
NS_IMETHOD GetIsStore(nsIMdbEnv* ev, mdb_bool* outBool);
|
||||
NS_IMETHOD GetIsStoreAndDirty(nsIMdbEnv* ev, mdb_bool* outBool);
|
||||
|
||||
NS_IMETHOD GetUsagePolicy(nsIMdbEnv* ev,
|
||||
mdbUsagePolicy* ioUsagePolicy);
|
||||
|
||||
NS_IMETHOD SetUsagePolicy(nsIMdbEnv* ev,
|
||||
const mdbUsagePolicy* inUsagePolicy);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin memory policy methods -----
|
||||
NS_IMETHOD IdleMemoryPurge( // do memory management already scheduled
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
|
||||
|
||||
NS_IMETHOD SessionMemoryPurge( // request specific footprint decrease
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_size inDesiredBytesFreed, // approximate number of bytes wanted
|
||||
mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
|
||||
|
||||
NS_IMETHOD PanicMemoryPurge( // desperately free all possible memory
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_size* outEstimatedBytesFreed); // approximate bytes actually freed
|
||||
// } ----- end memory policy methods -----
|
||||
|
||||
// { ----- begin filepath methods -----
|
||||
NS_IMETHOD GetPortFilePath(
|
||||
nsIMdbEnv* ev, // context
|
||||
mdbYarn* outFilePath, // name of file holding port content
|
||||
mdbYarn* outFormatVersion); // file format description
|
||||
|
||||
NS_IMETHOD GetPortFile(
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbFile** acqFile); // acquire file used by port or store
|
||||
// } ----- end filepath methods -----
|
||||
|
||||
// { ----- begin export methods -----
|
||||
NS_IMETHOD BestExportFormat( // determine preferred export format
|
||||
nsIMdbEnv* ev, // context
|
||||
mdbYarn* outFormatVersion); // file format description
|
||||
|
||||
NS_IMETHOD
|
||||
CanExportToFormat( // can export content in given specific format?
|
||||
nsIMdbEnv* ev, // context
|
||||
const char* inFormatVersion, // file format description
|
||||
mdb_bool* outCanExport); // whether ExportSource() might succeed
|
||||
|
||||
NS_IMETHOD ExportToFormat( // export content in given specific format
|
||||
nsIMdbEnv* ev, // context
|
||||
// const char* inFilePath, // the file to receive exported content
|
||||
nsIMdbFile* ioFile, // destination abstract file interface
|
||||
const char* inFormatVersion, // file format description
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental export
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the export will be finished.
|
||||
|
||||
// } ----- end export methods -----
|
||||
|
||||
// { ----- begin token methods -----
|
||||
NS_IMETHOD TokenToString( // return a string name for an integer token
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_token inToken, // token for inTokenName inside this port
|
||||
mdbYarn* outTokenName); // the type of table to access
|
||||
|
||||
NS_IMETHOD StringToToken( // return an integer token for scope name
|
||||
nsIMdbEnv* ev, // context
|
||||
const char* inTokenName, // Latin1 string to tokenize if possible
|
||||
mdb_token* outToken); // token for inTokenName inside this port
|
||||
|
||||
// String token zero is never used and never supported. If the port
|
||||
// is a mutable store, then StringToToken() to create a new
|
||||
// association of inTokenName with a new integer token if possible.
|
||||
// But a readonly port will return zero for an unknown scope name.
|
||||
|
||||
NS_IMETHOD QueryToken( // like StringToToken(), but without adding
|
||||
nsIMdbEnv* ev, // context
|
||||
const char* inTokenName, // Latin1 string to tokenize if possible
|
||||
mdb_token* outToken); // token for inTokenName inside this port
|
||||
|
||||
// QueryToken() will return a string token if one already exists,
|
||||
// but unlike StringToToken(), will not assign a new token if not
|
||||
// already in use.
|
||||
|
||||
// } ----- end token methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHOD HasRow( // contains a row with the specified oid?
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // hypothetical row oid
|
||||
mdb_bool* outHasRow); // whether GetRow() might succeed
|
||||
|
||||
NS_IMETHOD GetRowRefCount( // get number of tables that contain a row
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // hypothetical row oid
|
||||
mdb_count* outRefCount); // number of tables containing inRowKey
|
||||
|
||||
NS_IMETHOD GetRow( // access one row with specific oid
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // hypothetical row oid
|
||||
nsIMdbRow** acqRow); // acquire specific row (or null)
|
||||
|
||||
NS_IMETHOD FindRow(nsIMdbEnv* ev, // search for row with matching cell
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_column inColumn, // the column to search (and maintain an index)
|
||||
const mdbYarn* inTargetCellValue, // cell value for which to search
|
||||
mdbOid* outRowOid, // out row oid on match (or {0,-1} for no match)
|
||||
nsIMdbRow** acqRow); // acquire matching row (or nil for no match)
|
||||
// can be null if you only want the oid
|
||||
// FindRow() searches for one row that has a cell in column inColumn with
|
||||
// a contained value with the same form (i.e. charset) and is byte-wise
|
||||
// identical to the blob described by yarn inTargetCellValue. Both content
|
||||
// and form of the yarn must be an exact match to find a matching row.
|
||||
//
|
||||
// (In other words, both a yarn's blob bytes and form are significant. The
|
||||
// form is not expected to vary in columns used for identity anyway. This
|
||||
// is intended to make the cost of FindRow() cheaper for MDB implementors,
|
||||
// since any cell value atomization performed internally must necessarily
|
||||
// make yarn form significant in order to avoid data loss in atomization.)
|
||||
//
|
||||
// FindRow() can lazily create an index on attribute inColumn for all rows
|
||||
// with that attribute in row space scope inRowScope, so that subsequent
|
||||
// calls to FindRow() will perform faster. Such an index might or might
|
||||
// not be persistent (but this seems desirable if it is cheap to do so).
|
||||
// Note that lazy index creation in readonly DBs is not very feasible.
|
||||
//
|
||||
// This FindRow() interface assumes that attribute inColumn is effectively
|
||||
// an alternative means of unique identification for a row in a rowspace,
|
||||
// so correct behavior is only guaranteed when no duplicates for this col
|
||||
// appear in the given set of rows. (If more than one row has the same cell
|
||||
// value in this column, no more than one will be found; and cutting one of
|
||||
// two duplicate rows can cause the index to assume no other such row lives
|
||||
// in the row space, so future calls return nil for negative search results
|
||||
// even though some duplicate row might still live within the rowspace.)
|
||||
//
|
||||
// In other words, the FindRow() implementation is allowed to assume simple
|
||||
// hash tables mapping unqiue column keys to associated row values will be
|
||||
// sufficient, where any duplication is not recorded because only one copy
|
||||
// of a given key need be remembered. Implementors are not required to sort
|
||||
// all rows by the specified column.
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin table methods -----
|
||||
NS_IMETHOD HasTable( // supports a table with the specified oid?
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // hypothetical table oid
|
||||
mdb_bool* outHasTable); // whether GetTable() might succeed
|
||||
|
||||
NS_IMETHOD GetTable( // access one table with specific oid
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // hypothetical table oid
|
||||
nsIMdbTable** acqTable); // acquire specific table (or null)
|
||||
|
||||
NS_IMETHOD HasTableKind( // supports a table of the specified type?
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inRowScope, // rid scope for row ids
|
||||
mdb_kind inTableKind, // the type of table to access
|
||||
mdb_count* outTableCount, // current number of such tables
|
||||
mdb_bool* outSupportsTable); // whether GetTableKind() might succeed
|
||||
|
||||
NS_IMETHOD GetTableKind( // access one (random) table of specific type
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_kind inTableKind, // the type of table to access
|
||||
mdb_count* outTableCount, // current number of such tables
|
||||
mdb_bool* outMustBeUnique, // whether port can hold only one of these
|
||||
nsIMdbTable** acqTable); // acquire scoped collection of rows
|
||||
|
||||
NS_IMETHOD
|
||||
GetPortTableCursor( // get cursor for all tables of specific type
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_kind inTableKind, // the type of table to access
|
||||
nsIMdbPortTableCursor** acqCursor); // all such tables in the port
|
||||
// } ----- end table methods -----
|
||||
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
|
||||
NS_IMETHOD ShouldCompress( // store wastes at least inPercentWaste?
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_percent inPercentWaste, // 0..100 percent file size waste threshold
|
||||
mdb_percent* outActualWaste, // 0..100 percent of file actually wasted
|
||||
mdb_bool* outShould); // true when about inPercentWaste% is wasted
|
||||
// ShouldCompress() returns true if the store can determine that the file
|
||||
// will shrink by an estimated percentage of inPercentWaste% (or more) if
|
||||
// CompressCommit() is called, because that percentage of the file seems
|
||||
// to be recoverable free space. The granularity is only in terms of
|
||||
// percentage points, and any value over 100 is considered equal to 100.
|
||||
//
|
||||
// If a store only has an approximate idea how much space might be saved
|
||||
// during a compress, then a best guess should be made. For example, the
|
||||
// Mork implementation might keep track of how much file space began with
|
||||
// text content before the first updating transaction, and then consider
|
||||
// all content following the start of the first transaction as potentially
|
||||
// wasted space if it is all updates and not just new content. (This is
|
||||
// a safe assumption in the sense that behavior will stabilize on a low
|
||||
// estimate of wastage after a commit removes all transaction updates.)
|
||||
//
|
||||
// Some db formats might attempt to keep a very accurate reckoning of free
|
||||
// space size, so a very accurate determination can be made. But other db
|
||||
// formats might have difficulty determining size of free space, and might
|
||||
// require some lengthy calculation to answer. This is the reason for
|
||||
// passing in the percentage threshold of interest, so that such lengthy
|
||||
// computations can terminate early as soon as at least inPercentWaste is
|
||||
// found, so that the entire file need not be groveled when unnecessary.
|
||||
// However, we hope implementations will always favor fast but imprecise
|
||||
// heuristic answers instead of extremely slow but very precise answers.
|
||||
//
|
||||
// If the outActualWaste parameter is non-nil, it will be used to return
|
||||
// the actual estimated space wasted as a percentage of file size. (This
|
||||
// parameter is provided so callers need not call repeatedly with altered
|
||||
// inPercentWaste values to isolate the actual wastage figure.) Note the
|
||||
// actual wastage figure returned can exactly equal inPercentWaste even
|
||||
// when this grossly underestimates the real figure involved, if the db
|
||||
// finds it very expensive to determine the extent of wastage after it is
|
||||
// known to at least exceed inPercentWaste. Note we expect that whenever
|
||||
// outShould returns true, that outActualWaste returns >= inPercentWaste.
|
||||
//
|
||||
// The effect of different inPercentWaste values is not very uniform over
|
||||
// the permitted range. For example, 50 represents 50% wastage, or a file
|
||||
// that is about double what it should be ideally. But 99 represents 99%
|
||||
// wastage, or a file that is about ninety-nine times as big as it should
|
||||
// be ideally. In the smaller direction, 25 represents 25% wastage, or
|
||||
// a file that is only 33% larger than it should be ideally.
|
||||
//
|
||||
// Callers can determine what policy they want to use for considering when
|
||||
// a file holds too much wasted space, and express this as a percentage
|
||||
// of total file size to pass as in the inPercentWaste parameter. A zero
|
||||
// likely returns always trivially true, and 100 always trivially false.
|
||||
// The great majority of callers are expected to use values from 25 to 75,
|
||||
// since most plausible thresholds for compressing might fall between the
|
||||
// extremes of 133% of ideal size and 400% of ideal size. (Presumably the
|
||||
// larger a file gets, the more important the percentage waste involved, so
|
||||
// a sliding scale for compress thresholds might use smaller numbers for
|
||||
// much bigger file sizes.)
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbPort methods =====
|
||||
|
||||
// { ===== begin nsIMdbStore methods =====
|
||||
|
||||
// { ----- begin table methods -----
|
||||
NS_IMETHOD NewTable( // make one new table of specific type
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_kind inTableKind, // the type of table to access
|
||||
mdb_bool inMustBeUnique, // whether store can hold only one of these
|
||||
const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
|
||||
nsIMdbTable** acqTable); // acquire scoped collection of rows
|
||||
|
||||
NS_IMETHOD NewTableWithOid( // make one new table of specific type
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // caller assigned oid
|
||||
mdb_kind inTableKind, // the type of table to access
|
||||
mdb_bool inMustBeUnique, // whether store can hold only one of these
|
||||
const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
|
||||
nsIMdbTable** acqTable); // acquire scoped collection of rows
|
||||
// } ----- end table methods -----
|
||||
|
||||
// { ----- begin row scope methods -----
|
||||
NS_IMETHOD RowScopeHasAssignedIds(nsIMdbEnv* ev,
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
|
||||
mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
|
||||
|
||||
NS_IMETHOD SetCallerAssignedIds(nsIMdbEnv* ev,
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
|
||||
mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
|
||||
|
||||
NS_IMETHOD SetStoreAssignedIds(nsIMdbEnv* ev,
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
mdb_bool* outCallerAssigned, // nonzero if caller assigned specified
|
||||
mdb_bool* outStoreAssigned); // nonzero if store db assigned specified
|
||||
// } ----- end row scope methods -----
|
||||
|
||||
// { ----- begin row methods -----
|
||||
NS_IMETHOD NewRowWithOid(nsIMdbEnv* ev, // new row w/ caller assigned oid
|
||||
const mdbOid* inOid, // caller assigned oid
|
||||
nsIMdbRow** acqRow); // create new row
|
||||
|
||||
NS_IMETHOD NewRow(nsIMdbEnv* ev, // new row with db assigned oid
|
||||
mdb_scope inRowScope, // row scope for row ids
|
||||
nsIMdbRow** acqRow); // create new row
|
||||
// Note this row must be added to some table or cell child before the
|
||||
// store is closed in order to make this row persist across sesssions.
|
||||
|
||||
// } ----- end row methods -----
|
||||
|
||||
// { ----- begin inport/export methods -----
|
||||
NS_IMETHOD ImportContent( // import content from port
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inRowScope, // scope for rows (or zero for all?)
|
||||
nsIMdbPort* ioPort, // the port with content to add to store
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental import
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the import will be finished.
|
||||
|
||||
NS_IMETHOD ImportFile( // import content from port
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbFile* ioFile, // the file with content to add to store
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental import
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the import will be finished.
|
||||
// } ----- end inport/export methods -----
|
||||
|
||||
// { ----- begin hinting methods -----
|
||||
NS_IMETHOD
|
||||
ShareAtomColumnsHint( // advise re shared column content atomizing
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_scope inScopeHint, // zero, or suggested shared namespace
|
||||
const mdbColumnSet* inColumnSet); // cols desired tokenized together
|
||||
|
||||
NS_IMETHOD
|
||||
AvoidAtomColumnsHint( // advise column with poor atomizing prospects
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbColumnSet* inColumnSet); // cols with poor atomizing prospects
|
||||
// } ----- end hinting methods -----
|
||||
|
||||
// { ----- begin commit methods -----
|
||||
NS_IMETHOD SmallCommit( // save minor changes if convenient and uncostly
|
||||
nsIMdbEnv* ev); // context
|
||||
|
||||
NS_IMETHOD LargeCommit( // save important changes if at all possible
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the commit will be finished. Note the store is effectively write
|
||||
// locked until commit is finished or canceled through the thumb instance.
|
||||
// Until the commit is done, the store will report it has readonly status.
|
||||
|
||||
NS_IMETHOD SessionCommit( // save all changes if large commits delayed
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the commit will be finished. Note the store is effectively write
|
||||
// locked until commit is finished or canceled through the thumb instance.
|
||||
// Until the commit is done, the store will report it has readonly status.
|
||||
|
||||
NS_IMETHOD
|
||||
CompressCommit( // commit and make db physically smaller if possible
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental commit
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the commit will be finished. Note the store is effectively write
|
||||
// locked until commit is finished or canceled through the thumb instance.
|
||||
// Until the commit is done, the store will report it has readonly status.
|
||||
|
||||
// } ----- end commit methods -----
|
||||
|
||||
// } ===== end nsIMdbStore methods =====
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakPort(morkPort* me,
|
||||
morkEnv* ev, morkPort** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongPort(morkPort* me,
|
||||
morkEnv* ev, morkPort** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
// public: // slots inherited from morkPort (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkEnv* mPort_Env; // non-refcounted env which created port
|
||||
// morkFactory* mPort_Factory; // weak ref to suite factory
|
||||
// nsIMdbHeap* mPort_Heap; // heap in which this port allocs objects
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
// mStore_OidAtomSpace might be unnecessary; I don't remember why I wanted it.
|
||||
morkAtomSpace* mStore_OidAtomSpace; // ground atom space for oids
|
||||
morkAtomSpace* mStore_GroundAtomSpace; // ground atom space for scopes
|
||||
morkAtomSpace* mStore_GroundColumnSpace; // ground column space for scopes
|
||||
|
||||
nsIMdbFile* mStore_File; // the file containing Mork text
|
||||
morkStream* mStore_InStream; // stream using file used by the builder
|
||||
morkBuilder* mStore_Builder; // to parse Mork text and build structures
|
||||
|
||||
morkStream* mStore_OutStream; // stream using file used by the writer
|
||||
|
||||
morkRowSpaceMap mStore_RowSpaces; // maps mork_scope -> morkSpace
|
||||
morkAtomSpaceMap mStore_AtomSpaces; // maps mork_scope -> morkSpace
|
||||
|
||||
morkZone mStore_Zone;
|
||||
|
||||
morkPool mStore_Pool;
|
||||
|
||||
// we alloc a max size book atom to reuse space for atom map key searches:
|
||||
// morkMaxBookAtom mStore_BookAtom; // staging area for atom map searches
|
||||
|
||||
morkFarBookAtom mStore_FarBookAtom; // staging area for atom map searches
|
||||
|
||||
// GroupIdentity should be one more than largest seen in a parsed db file:
|
||||
mork_gid mStore_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// group positions are used to help compute PercentOfStoreWasted():
|
||||
mork_pos mStore_FirstCommitGroupPos; // start of first group
|
||||
mork_pos mStore_SecondCommitGroupPos; // start of second group
|
||||
// If the first commit group is very near the start of the file (say less
|
||||
// than 512 bytes), then we might assume the file started nearly empty and
|
||||
// that most of the first group is not wasted. In that case, the pos of
|
||||
// the second commit group might make a better estimate of the start of
|
||||
// transaction space that might represent wasted file space. That's why
|
||||
// we support fields for both first and second commit group positions.
|
||||
//
|
||||
// We assume that a zero in either group pos means that the slot has not
|
||||
// yet been given a valid value, since the file will always start with a
|
||||
// tag, and a commit group cannot actually start at position zero.
|
||||
//
|
||||
// Either or both the first or second commit group positions might be
|
||||
// supplied by either morkWriter (while committing) or morkBuilder (while
|
||||
// parsing), since either reading or writing the file might encounter the
|
||||
// first transaction groups which came into existence either in the past
|
||||
// or in the very recent present.
|
||||
|
||||
mork_bool mStore_CanAutoAssignAtomIdentity;
|
||||
mork_bool mStore_CanDirty; // changes imply the store becomes dirty?
|
||||
mork_u1 mStore_CanWriteIncremental; // compress not required?
|
||||
mork_u1 mStore_Pad; // for u4 alignment
|
||||
|
||||
// mStore_CanDirty should be FALSE when parsing a file while building the
|
||||
// content going into the store, because such data structure modifications
|
||||
// are actuallly in sync with the file. So content read from a file must
|
||||
// be clean with respect to the file. After a file is finished parsing,
|
||||
// the mStore_CanDirty slot should become TRUE, so that any additional
|
||||
// changes at runtime cause structures to be marked dirty with respect to
|
||||
// the file which must later be updated with changes during a commit.
|
||||
//
|
||||
// It might also make sense to set mStore_CanDirty to FALSE while a commit
|
||||
// is in progress, lest some internal transformations make more content
|
||||
// appear dirty when it should not. So anyone modifying content during a
|
||||
// commit should think about the intended significance regarding dirty.
|
||||
|
||||
public: // more specific dirty methods for store:
|
||||
void SetStoreDirty() { this->SetNodeDirty(); }
|
||||
void SetStoreClean() { this->SetNodeClean(); }
|
||||
|
||||
mork_bool IsStoreClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsStoreDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // setting dirty based on CanDirty:
|
||||
|
||||
void MaybeDirtyStore()
|
||||
{ if ( mStore_CanDirty ) this->SetStoreDirty(); }
|
||||
|
||||
public: // space waste analysis
|
||||
|
||||
mork_percent PercentOfStoreWasted(morkEnv* ev);
|
||||
|
||||
public: // setting store and all subspaces canDirty:
|
||||
|
||||
void SetStoreAndAllSpacesCanDirty(morkEnv* ev, mork_bool inCanDirty);
|
||||
|
||||
public: // building an atom inside mStore_FarBookAtom from a char* string
|
||||
|
||||
morkFarBookAtom* StageAliasAsFarBookAtom(morkEnv* ev,
|
||||
const morkMid* inMid, morkAtomSpace* ioSpace, mork_cscode inForm);
|
||||
|
||||
morkFarBookAtom* StageYarnAsFarBookAtom(morkEnv* ev,
|
||||
const mdbYarn* inYarn, morkAtomSpace* ioSpace);
|
||||
|
||||
morkFarBookAtom* StageStringAsFarBookAtom(morkEnv* ev,
|
||||
const char* inString, mork_cscode inForm, morkAtomSpace* ioSpace);
|
||||
|
||||
public: // determining whether incremental writing is a good use of time:
|
||||
|
||||
mork_bool DoPreferLargeOverCompressCommit(morkEnv* ev);
|
||||
// true when mStore_CanWriteIncremental && store has file large enough
|
||||
|
||||
public: // lazy creation of members and nested row or atom spaces
|
||||
|
||||
morkAtomSpace* LazyGetOidAtomSpace(morkEnv* ev);
|
||||
morkAtomSpace* LazyGetGroundAtomSpace(morkEnv* ev);
|
||||
morkAtomSpace* LazyGetGroundColumnSpace(morkEnv* ev);
|
||||
|
||||
morkStream* LazyGetInStream(morkEnv* ev);
|
||||
morkBuilder* LazyGetBuilder(morkEnv* ev);
|
||||
void ForgetBuilder(morkEnv* ev);
|
||||
|
||||
morkStream* LazyGetOutStream(morkEnv* ev);
|
||||
|
||||
morkRowSpace* LazyGetRowSpace(morkEnv* ev, mdb_scope inRowScope);
|
||||
morkAtomSpace* LazyGetAtomSpace(morkEnv* ev, mdb_scope inAtomScope);
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseStore() only if open
|
||||
virtual ~morkStore(); // assert that CloseStore() executed earlier
|
||||
|
||||
public: // morkStore construction & destruction
|
||||
morkStore(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap, // the heap (if any) for this node instance
|
||||
morkFactory* inFactory, // the factory for this
|
||||
nsIMdbHeap* ioPortHeap // the heap to hold all content in the port
|
||||
);
|
||||
void CloseStore(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkStore(const morkStore& other);
|
||||
morkStore& operator=(const morkStore& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
morkEnv* CanUseStore(nsIMdbEnv* mev, mork_bool inMutable, mdb_err* outErr) const;
|
||||
mork_bool IsStore() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kStore; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonStoreTypeError(morkEnv* ev);
|
||||
static void NilStoreFileError(morkEnv* ev);
|
||||
static void CannotAutoAssignAtomIdentityError(morkEnv* ev);
|
||||
|
||||
public: // store utilties
|
||||
|
||||
morkAtom* YarnToAtom(morkEnv* ev, const mdbYarn* inYarn, PRBool createIfMissing = PR_TRUE);
|
||||
morkAtom* AddAlias(morkEnv* ev, const morkMid& inMid,
|
||||
mork_cscode inForm);
|
||||
|
||||
public: // other store methods
|
||||
|
||||
void RenumberAllCollectableContent(morkEnv* ev);
|
||||
|
||||
nsIMdbStore* AcquireStoreHandle(morkEnv* ev); // mObject_Handle
|
||||
|
||||
morkPool* StorePool() { return &mStore_Pool; }
|
||||
|
||||
mork_bool OpenStoreFile(morkEnv* ev, // return value equals ev->Good()
|
||||
mork_bool inFrozen,
|
||||
// const char* inFilePath,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy);
|
||||
|
||||
mork_bool CreateStoreFile(morkEnv* ev, // return value equals ev->Good()
|
||||
// const char* inFilePath,
|
||||
nsIMdbFile* ioFile, // db abstract file interface
|
||||
const mdbOpenPolicy* inOpenPolicy);
|
||||
|
||||
morkAtom* CopyAtom(morkEnv* ev, const morkAtom* inAtom);
|
||||
// copy inAtom (from some other store) over to this store
|
||||
|
||||
mork_token CopyToken(morkEnv* ev, mdb_token inToken, morkStore* inStore);
|
||||
// copy inToken from inStore over to this store
|
||||
|
||||
mork_token BufToToken(morkEnv* ev, const morkBuf* inBuf);
|
||||
mork_token StringToToken(morkEnv* ev, const char* inTokenName);
|
||||
mork_token QueryToken(morkEnv* ev, const char* inTokenName);
|
||||
void TokenToString(morkEnv* ev, mdb_token inToken, mdbYarn* outTokenName);
|
||||
|
||||
mork_bool MidToOid(morkEnv* ev, const morkMid& inMid,
|
||||
mdbOid* outOid);
|
||||
mork_bool OidToYarn(morkEnv* ev, const mdbOid& inOid, mdbYarn* outYarn);
|
||||
mork_bool MidToYarn(morkEnv* ev, const morkMid& inMid,
|
||||
mdbYarn* outYarn);
|
||||
|
||||
morkBookAtom* MidToAtom(morkEnv* ev, const morkMid& inMid);
|
||||
morkRow* MidToRow(morkEnv* ev, const morkMid& inMid);
|
||||
morkTable* MidToTable(morkEnv* ev, const morkMid& inMid);
|
||||
|
||||
morkRow* OidToRow(morkEnv* ev, const mdbOid* inOid);
|
||||
// OidToRow() finds old row with oid, or makes new one if not found.
|
||||
|
||||
morkTable* OidToTable(morkEnv* ev, const mdbOid* inOid,
|
||||
const mdbOid* inOptionalMetaRowOid);
|
||||
// OidToTable() finds old table with oid, or makes new one if not found.
|
||||
|
||||
static void SmallTokenToOneByteYarn(morkEnv* ev, mdb_token inToken,
|
||||
mdbYarn* outYarn);
|
||||
|
||||
mork_bool HasTableKind(morkEnv* ev, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind, mdb_count* outTableCount);
|
||||
|
||||
morkTable* GetTableKind(morkEnv* ev, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind, mdb_count* outTableCount,
|
||||
mdb_bool* outMustBeUnique);
|
||||
|
||||
morkRow* FindRow(morkEnv* ev, mdb_scope inScope, mdb_column inColumn,
|
||||
const mdbYarn* inTargetCellValue);
|
||||
|
||||
morkRow* GetRow(morkEnv* ev, const mdbOid* inOid);
|
||||
morkTable* GetTable(morkEnv* ev, const mdbOid* inOid);
|
||||
|
||||
morkTable* NewTable(morkEnv* ev, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind, mdb_bool inMustBeUnique,
|
||||
const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
morkPortTableCursor* GetPortTableCursor(morkEnv* ev, mdb_scope inRowScope,
|
||||
mdb_kind inTableKind) ;
|
||||
|
||||
morkRow* NewRowWithOid(morkEnv* ev, const mdbOid* inOid);
|
||||
morkRow* NewRow(morkEnv* ev, mdb_scope inRowScope);
|
||||
|
||||
morkThumb* MakeCompressCommitThumb(morkEnv* ev, mork_bool inDoCollect);
|
||||
|
||||
public: // commit related methods
|
||||
|
||||
mork_bool MarkAllStoreContentDirty(morkEnv* ev);
|
||||
// MarkAllStoreContentDirty() visits every object in the store and marks
|
||||
// them dirty, including every table, row, cell, and atom. The return
|
||||
// equals ev->Good(), to show whether any error happened. This method is
|
||||
// intended for use in the beginning of a "compress commit" which writes
|
||||
// all store content, whether dirty or not. We dirty everything first so
|
||||
// that later iterations over content can mark things clean as they are
|
||||
// written, and organize the process of serialization so that objects are
|
||||
// written only at need (because of being dirty).
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakStore(morkStore* me,
|
||||
morkEnv* ev, morkStore** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongStore(morkStore* me,
|
||||
morkEnv* ev, morkStore** ioSlot)
|
||||
{
|
||||
morkStore* store = *ioSlot;
|
||||
if ( me != store )
|
||||
{
|
||||
if ( store )
|
||||
{
|
||||
// what if this nulls out the ev and causes asserts?
|
||||
// can we move this after the CutStrongRef()?
|
||||
*ioSlot = 0;
|
||||
store->Release();
|
||||
}
|
||||
if ( me && me->AddRef() )
|
||||
*ioSlot = me;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKSTORE_ */
|
||||
|
|
@ -0,0 +1,896 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTREAM_
|
||||
#include "morkStream.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkStream::CloseMorkNode(morkEnv* ev) // CloseStream() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseStream(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkStream::~morkStream() // assert CloseStream() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mStream_ContentFile==0);
|
||||
MORK_ASSERT(mStream_Buf==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkStream::morkStream(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile* ioContentFile, mork_size inBufSize, mork_bool inFrozen)
|
||||
: morkFile(ev, inUsage, ioHeap, ioHeap)
|
||||
, mStream_At( 0 )
|
||||
, mStream_ReadEnd( 0 )
|
||||
, mStream_WriteEnd( 0 )
|
||||
|
||||
, mStream_ContentFile( 0 )
|
||||
|
||||
, mStream_Buf( 0 )
|
||||
, mStream_BufSize( inBufSize )
|
||||
, mStream_BufPos( 0 )
|
||||
, mStream_Dirty( morkBool_kFalse )
|
||||
, mStream_HitEof( morkBool_kFalse )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( inBufSize < morkStream_kMinBufSize )
|
||||
mStream_BufSize = inBufSize = morkStream_kMinBufSize;
|
||||
else if ( inBufSize > morkStream_kMaxBufSize )
|
||||
mStream_BufSize = inBufSize = morkStream_kMaxBufSize;
|
||||
|
||||
if ( ioContentFile && ioHeap )
|
||||
{
|
||||
// if ( ioContentFile->FileFrozen() ) // forced to be readonly?
|
||||
// inFrozen = morkBool_kTrue; // override the input value
|
||||
|
||||
nsIMdbFile_SlotStrongFile(ioContentFile, ev, &mStream_ContentFile);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mork_u1* buf = 0;
|
||||
ioHeap->Alloc(ev->AsMdbEnv(), inBufSize, (void**) &buf);
|
||||
if ( buf )
|
||||
{
|
||||
mStream_At = mStream_Buf = buf;
|
||||
|
||||
if ( !inFrozen )
|
||||
{
|
||||
// physical buffer end never moves:
|
||||
mStream_WriteEnd = buf + inBufSize;
|
||||
}
|
||||
else
|
||||
mStream_WriteEnd = 0; // no writing is allowed
|
||||
|
||||
if ( inFrozen )
|
||||
{
|
||||
// logical buffer end starts at Buf with no content:
|
||||
mStream_ReadEnd = buf;
|
||||
this->SetFileFrozen(inFrozen);
|
||||
}
|
||||
else
|
||||
mStream_ReadEnd = 0; // no reading is allowed
|
||||
|
||||
this->SetFileActive(morkBool_kTrue);
|
||||
this->SetFileIoOpen(morkBool_kTrue);
|
||||
}
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kStream;
|
||||
}
|
||||
}
|
||||
else ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkStream::CloseStream(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mStream_ContentFile);
|
||||
nsIMdbHeap* heap = mFile_SlotHeap;
|
||||
mork_u1* buf = mStream_Buf;
|
||||
mStream_Buf = 0;
|
||||
|
||||
if ( heap && buf )
|
||||
heap->Free(ev->AsMdbEnv(), buf);
|
||||
|
||||
this->CloseFile(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
#define morkStream_kSpacesPerIndent 1 /* one space per indent */
|
||||
#define morkStream_kMaxIndentDepth 70 /* max indent of 70 space bytes */
|
||||
static const char morkStream_kSpaces[] // next line to ease length perception
|
||||
= " ";
|
||||
// 123456789_123456789_123456789_123456789_123456789_123456789_123456789_
|
||||
// morkStream_kSpaces above must contain (at least) 70 spaces (ASCII 0x20)
|
||||
|
||||
mork_size
|
||||
morkStream::PutIndent(morkEnv* ev, mork_count inDepth)
|
||||
// PutIndent() puts a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
{
|
||||
mork_size outLength = 0;
|
||||
nsIMdbEnv *mev = ev->AsMdbEnv();
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->PutLineBreak(ev);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
outLength = inDepth;
|
||||
mdb_size bytesWritten;
|
||||
if ( inDepth )
|
||||
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
|
||||
}
|
||||
}
|
||||
return outLength;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutByteThenIndent(morkEnv* ev, int inByte, mork_count inDepth)
|
||||
// PutByteThenIndent() puts the byte, then a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
{
|
||||
mork_size outLength = 0;
|
||||
nsIMdbEnv *mev = ev->AsMdbEnv();
|
||||
|
||||
if ( inDepth > morkStream_kMaxIndentDepth )
|
||||
inDepth = morkStream_kMaxIndentDepth;
|
||||
|
||||
this->Putc(ev, inByte);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->PutLineBreak(ev);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
outLength = inDepth;
|
||||
mdb_size bytesWritten;
|
||||
if ( inDepth )
|
||||
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
|
||||
}
|
||||
}
|
||||
return outLength;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutStringThenIndent(morkEnv* ev,
|
||||
const char* inString, mork_count inDepth)
|
||||
// PutStringThenIndent() puts the string, then a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
{
|
||||
mork_size outLength = 0;
|
||||
mdb_size bytesWritten;
|
||||
nsIMdbEnv *mev = ev->AsMdbEnv();
|
||||
|
||||
if ( inDepth > morkStream_kMaxIndentDepth )
|
||||
inDepth = morkStream_kMaxIndentDepth;
|
||||
|
||||
if ( inString )
|
||||
{
|
||||
mork_size length = MORK_STRLEN(inString);
|
||||
if ( length && ev->Good() ) // any bytes to write?
|
||||
this->Write(mev, inString, length, &bytesWritten);
|
||||
}
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
this->PutLineBreak(ev);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
outLength = inDepth;
|
||||
if ( inDepth )
|
||||
this->Write(mev, morkStream_kSpaces, inDepth, &bytesWritten);
|
||||
}
|
||||
}
|
||||
return outLength;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutString(morkEnv* ev, const char* inString)
|
||||
{
|
||||
nsIMdbEnv *mev = ev->AsMdbEnv();
|
||||
mork_size outSize = 0;
|
||||
mdb_size bytesWritten;
|
||||
if ( inString )
|
||||
{
|
||||
outSize = MORK_STRLEN(inString);
|
||||
if ( outSize && ev->Good() ) // any bytes to write?
|
||||
{
|
||||
this->Write(mev, inString, outSize, &bytesWritten);
|
||||
}
|
||||
}
|
||||
return outSize;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutStringThenNewline(morkEnv* ev, const char* inString)
|
||||
// PutStringThenNewline() returns total number of bytes written.
|
||||
{
|
||||
nsIMdbEnv *mev = ev->AsMdbEnv();
|
||||
mork_size outSize = 0;
|
||||
mdb_size bytesWritten;
|
||||
if ( inString )
|
||||
{
|
||||
outSize = MORK_STRLEN(inString);
|
||||
if ( outSize && ev->Good() ) // any bytes to write?
|
||||
{
|
||||
this->Write(mev, inString, outSize, &bytesWritten);
|
||||
if ( ev->Good() )
|
||||
outSize += this->PutLineBreak(ev);
|
||||
}
|
||||
}
|
||||
return outSize;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutByteThenNewline(morkEnv* ev, int inByte)
|
||||
// PutByteThenNewline() returns total number of bytes written.
|
||||
{
|
||||
mork_size outSize = 1; // one for the following byte
|
||||
this->Putc(ev, inByte);
|
||||
if ( ev->Good() )
|
||||
outSize += this->PutLineBreak(ev);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
mork_size
|
||||
morkStream::PutLineBreak(morkEnv* ev)
|
||||
{
|
||||
#if defined(MORK_MAC)
|
||||
|
||||
this->Putc(ev, mork_kCR);
|
||||
return 1;
|
||||
|
||||
#else
|
||||
# if defined(MORK_WIN) || defined(MORK_OS2)
|
||||
|
||||
this->Putc(ev, mork_kCR);
|
||||
this->Putc(ev, mork_kLF);
|
||||
return 2;
|
||||
|
||||
# else
|
||||
# ifdef MORK_UNIX
|
||||
|
||||
this->Putc(ev, mork_kLF);
|
||||
return 1;
|
||||
|
||||
# endif /* MORK_UNIX */
|
||||
# endif /* MORK_WIN */
|
||||
#endif /* MORK_MAC */
|
||||
}
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
// public: // virtual morkFile methods
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Steal(nsIMdbEnv* mev, nsIMdbFile* ioThief)
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
{
|
||||
MORK_USED_1(ioThief);
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
ev->StubMethodOnlyError();
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::BecomeTrunk(nsIMdbEnv* mev)
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
{
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
ev->StubMethodOnlyError();
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::AcquireBud(nsIMdbEnv* mev, nsIMdbHeap* ioHeap, nsIMdbFile **acqBud)
|
||||
// AcquireBud() starts a new "branch" version of the file, empty of content,
|
||||
// so that a new version of the file can be written. This new file
|
||||
// can later be told to BecomeTrunk() the original file, so the branch
|
||||
// created by budding the file will replace the original file. Some
|
||||
// file subclasses might initially take the unsafe but expedient
|
||||
// approach of simply truncating this file down to zero length, and
|
||||
// then returning the same morkFile pointer as this, with an extra
|
||||
// reference count increment. Note that the caller of AcquireBud() is
|
||||
// expected to eventually call CutStrongRef() on the returned file
|
||||
// in order to release the strong reference. High quality versions
|
||||
// of morkFile subclasses will create entirely new files which later
|
||||
// are renamed to become the old file, so that better transactional
|
||||
// behavior is exhibited by the file, so crashes protect old files.
|
||||
// Note that AcquireBud() is an illegal operation on readonly files.
|
||||
{
|
||||
MORK_USED_1(ioHeap);
|
||||
morkFile* outFile = 0;
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( this->IsOpenAndActiveFile() && file )
|
||||
{
|
||||
// figure out how this interacts with buffering and mStream_WriteEnd:
|
||||
ev->StubMethodOnlyError();
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
*acqBud = outFile;
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
mork_pos
|
||||
morkStream::Length(morkEnv* ev) const // eof
|
||||
{
|
||||
mork_pos outPos = 0;
|
||||
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenAndActiveFile() && file )
|
||||
{
|
||||
mork_pos contentEof = 0;
|
||||
file->Eof(ev->AsMdbEnv(), &contentEof);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( mStream_WriteEnd ) // this stream supports writing?
|
||||
{
|
||||
// the local buffer might have buffered content past content eof
|
||||
if ( ev->Good() ) // no error happened during Length() above?
|
||||
{
|
||||
mork_u1* at = mStream_At;
|
||||
mork_u1* buf = mStream_Buf;
|
||||
if ( at >= buf ) // expected cursor order?
|
||||
{
|
||||
mork_pos localContent = mStream_BufPos + (at - buf);
|
||||
if ( localContent > contentEof ) // buffered past eof?
|
||||
contentEof = localContent; // return new logical eof
|
||||
|
||||
outPos = contentEof;
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
}
|
||||
else
|
||||
outPos = contentEof; // frozen files get length from content file
|
||||
}
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
return outPos;
|
||||
}
|
||||
|
||||
void morkStream::NewBadCursorSlotsError(morkEnv* ev) const
|
||||
{ ev->NewError("bad stream cursor slots"); }
|
||||
|
||||
void morkStream::NewNullStreamBufferError(morkEnv* ev) const
|
||||
{ ev->NewError("null stream buffer"); }
|
||||
|
||||
void morkStream::NewCantReadSinkError(morkEnv* ev) const
|
||||
{ ev->NewError("cant read stream sink"); }
|
||||
|
||||
void morkStream::NewCantWriteSourceError(morkEnv* ev) const
|
||||
{ ev->NewError("cant write stream source"); }
|
||||
|
||||
void morkStream::NewPosBeyondEofError(morkEnv* ev) const
|
||||
{ ev->NewError("stream pos beyond eof"); }
|
||||
|
||||
void morkStream::NewBadCursorOrderError(morkEnv* ev) const
|
||||
{ ev->NewError("bad stream cursor order"); }
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Tell(nsIMdbEnv* mdbev, mork_pos *aOutPos) const
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aOutPos);
|
||||
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenAndActiveFile() && file )
|
||||
{
|
||||
mork_u1* buf = mStream_Buf;
|
||||
mork_u1* at = mStream_At;
|
||||
|
||||
mork_u1* readEnd = mStream_ReadEnd; // nonzero only if readonly
|
||||
mork_u1* writeEnd = mStream_WriteEnd; // nonzero only if writeonly
|
||||
|
||||
if ( writeEnd )
|
||||
{
|
||||
if ( buf && at >= buf && at <= writeEnd )
|
||||
{
|
||||
*aOutPos = mStream_BufPos + (at - buf);
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
else if ( readEnd )
|
||||
{
|
||||
if ( buf && at >= buf && at <= readEnd )
|
||||
{
|
||||
*aOutPos = mStream_BufPos + (at - buf);
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Read(nsIMdbEnv* mdbev, void* outBuf, mork_size inSize, mork_size *aOutSize)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOutSize);
|
||||
// First we satisfy the request from buffered bytes, if any. Then
|
||||
// if additional bytes are needed, we satisfy these by direct reads
|
||||
// from the content file without any local buffering (but we still need
|
||||
// to adjust the buffer position to reflect the current i/o point).
|
||||
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenAndActiveFile() && file )
|
||||
{
|
||||
mork_u1* end = mStream_ReadEnd; // byte after last buffered byte
|
||||
if ( end ) // file is open for read access?
|
||||
{
|
||||
if ( inSize ) // caller wants any output?
|
||||
{
|
||||
mork_u1* sink = (mork_u1*) outBuf; // where we plan to write bytes
|
||||
if ( sink ) // caller passed good buffer address?
|
||||
{
|
||||
mork_u1* at = mStream_At;
|
||||
mork_u1* buf = mStream_Buf;
|
||||
if ( at >= buf && at <= end ) // expected cursor order?
|
||||
{
|
||||
mork_num remaining = (mork_num) (end - at); // bytes left in buffer
|
||||
|
||||
mork_num quantum = inSize; // number of bytes to copy
|
||||
if ( quantum > remaining ) // more than buffer content?
|
||||
quantum = remaining; // restrict to buffered bytes
|
||||
|
||||
if ( quantum ) // any bytes left in the buffer?
|
||||
{
|
||||
MORK_MEMCPY(sink, at, quantum); // from buffer bytes
|
||||
|
||||
at += quantum; // advance past read bytes
|
||||
mStream_At = at;
|
||||
*aOutSize += quantum; // this much copied so far
|
||||
|
||||
sink += quantum; // in case we need to copy more
|
||||
inSize -= quantum; // filled this much of request
|
||||
mStream_HitEof = morkBool_kFalse;
|
||||
}
|
||||
|
||||
if ( inSize ) // we still need to read more content?
|
||||
{
|
||||
// We need to read more bytes directly from the
|
||||
// content file, without local buffering. We have
|
||||
// exhausted the local buffer, so we need to show
|
||||
// it is now empty, and adjust the current buf pos.
|
||||
|
||||
mork_num posDelta = (mork_num) (at - buf); // old buf content
|
||||
mStream_BufPos += posDelta; // past now empty buf
|
||||
|
||||
mStream_At = mStream_ReadEnd = buf; // empty buffer
|
||||
|
||||
// file->Seek(ev, mStream_BufPos); // set file pos
|
||||
// if ( ev->Good() ) // no seek error?
|
||||
// {
|
||||
// }
|
||||
|
||||
mork_num actual = 0;
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
file->Get(menv, sink, inSize, mStream_BufPos, &actual);
|
||||
if ( ev->Good() ) // no read error?
|
||||
{
|
||||
if ( actual )
|
||||
{
|
||||
*aOutSize += actual;
|
||||
mStream_BufPos += actual;
|
||||
mStream_HitEof = morkBool_kFalse;
|
||||
}
|
||||
else if ( !*aOutSize )
|
||||
mStream_HitEof = morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
else this->NewNullStreamBufferError(ev);
|
||||
}
|
||||
}
|
||||
else this->NewCantReadSinkError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
if ( ev->Bad() )
|
||||
*aOutSize = 0;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Seek(nsIMdbEnv * mdbev, mork_pos inPos, mork_pos *aOutPos)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOutPos);
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(mdbev);
|
||||
*aOutPos = 0;
|
||||
nsresult rv = NS_OK;
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
|
||||
{
|
||||
mork_u1* at = mStream_At; // current position in buffer
|
||||
mork_u1* buf = mStream_Buf; // beginning of buffer
|
||||
mork_u1* readEnd = mStream_ReadEnd; // nonzero only if readonly
|
||||
mork_u1* writeEnd = mStream_WriteEnd; // nonzero only if writeonly
|
||||
|
||||
if ( writeEnd ) // file is mutable/writeonly?
|
||||
{
|
||||
if ( mStream_Dirty ) // need to commit buffer changes?
|
||||
this->Flush(mdbev);
|
||||
|
||||
if ( ev->Good() ) // no errors during flush or earlier?
|
||||
{
|
||||
if ( at == buf ) // expected post flush cursor value?
|
||||
{
|
||||
if ( mStream_BufPos != inPos ) // need to change pos?
|
||||
{
|
||||
mork_pos eof = 0;
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
file->Eof(menv, &eof);
|
||||
if ( ev->Good() ) // no errors getting length?
|
||||
{
|
||||
if ( inPos <= eof ) // acceptable new position?
|
||||
{
|
||||
mStream_BufPos = inPos; // new stream position
|
||||
*aOutPos = inPos;
|
||||
}
|
||||
else this->NewPosBeyondEofError(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
}
|
||||
else if ( readEnd ) // file is frozen/readonly?
|
||||
{
|
||||
if ( at >= buf && at <= readEnd ) // expected cursor order?
|
||||
{
|
||||
mork_pos eof = 0;
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
file->Eof(menv, &eof);
|
||||
if ( ev->Good() ) // no errors getting length?
|
||||
{
|
||||
if ( inPos <= eof ) // acceptable new position?
|
||||
{
|
||||
*aOutPos = inPos;
|
||||
mStream_BufPos = inPos; // new stream position
|
||||
mStream_At = mStream_ReadEnd = buf; // empty buffer
|
||||
if ( inPos == eof ) // notice eof reached?
|
||||
mStream_HitEof = morkBool_kTrue;
|
||||
}
|
||||
else this->NewPosBeyondEofError(ev);
|
||||
}
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Write(nsIMdbEnv* menv, const void* inBuf, mork_size inSize, mork_size *aOutSize)
|
||||
{
|
||||
mork_num outActual = 0;
|
||||
morkEnv *ev = morkEnv::FromMdbEnv(menv);
|
||||
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenActiveAndMutableFile() && file )
|
||||
{
|
||||
mork_u1* end = mStream_WriteEnd; // byte after last buffered byte
|
||||
if ( end ) // file is open for write access?
|
||||
{
|
||||
if ( inSize ) // caller provided any input?
|
||||
{
|
||||
const mork_u1* source = (const mork_u1*) inBuf; // from where
|
||||
if ( source ) // caller passed good buffer address?
|
||||
{
|
||||
mork_u1* at = mStream_At;
|
||||
mork_u1* buf = mStream_Buf;
|
||||
if ( at >= buf && at <= end ) // expected cursor order?
|
||||
{
|
||||
mork_num space = (mork_num) (end - at); // space left in buffer
|
||||
|
||||
mork_num quantum = inSize; // number of bytes to write
|
||||
if ( quantum > space ) // more than buffer size?
|
||||
quantum = space; // restrict to avail space
|
||||
|
||||
if ( quantum ) // any space left in the buffer?
|
||||
{
|
||||
mStream_Dirty = morkBool_kTrue; // to ensure later flush
|
||||
MORK_MEMCPY(at, source, quantum); // into buffer
|
||||
|
||||
mStream_At += quantum; // advance past written bytes
|
||||
outActual += quantum; // this much written so far
|
||||
|
||||
source += quantum; // in case we need to write more
|
||||
inSize -= quantum; // filled this much of request
|
||||
}
|
||||
|
||||
if ( inSize ) // we still need to write more content?
|
||||
{
|
||||
// We need to write more bytes directly to the
|
||||
// content file, without local buffering. We have
|
||||
// exhausted the local buffer, so we need to flush
|
||||
// it and empty it, and adjust the current buf pos.
|
||||
// After flushing, if the rest of the write fits
|
||||
// inside the buffer, we will put bytes into the
|
||||
// buffer rather than write them to content file.
|
||||
|
||||
if ( mStream_Dirty )
|
||||
this->Flush(menv); // will update mStream_BufPos
|
||||
|
||||
at = mStream_At;
|
||||
if ( at < buf || at > end ) // bad cursor?
|
||||
this->NewBadCursorOrderError(ev);
|
||||
|
||||
if ( ev->Good() ) // no errors?
|
||||
{
|
||||
space = (mork_num) (end - at); // space left in buffer
|
||||
if ( space > inSize ) // write to buffer?
|
||||
{
|
||||
mStream_Dirty = morkBool_kTrue; // ensure flush
|
||||
MORK_MEMCPY(at, source, inSize); // copy
|
||||
|
||||
mStream_At += inSize; // past written bytes
|
||||
outActual += inSize; // this much written
|
||||
}
|
||||
else // directly to content file instead
|
||||
{
|
||||
// file->Seek(ev, mStream_BufPos); // set pos
|
||||
// if ( ev->Good() ) // no seek error?
|
||||
// {
|
||||
// }
|
||||
|
||||
mork_num actual = 0;
|
||||
file->Put(menv, source, inSize, mStream_BufPos, &actual);
|
||||
if ( ev->Good() ) // no write error?
|
||||
{
|
||||
outActual += actual;
|
||||
mStream_BufPos += actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
else this->NewNullStreamBufferError(ev);
|
||||
}
|
||||
}
|
||||
else this->NewCantWriteSourceError(ev);
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
if ( ev->Bad() )
|
||||
outActual = 0;
|
||||
|
||||
*aOutSize = outActual;
|
||||
return ev->AsErr();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkStream::Flush(nsIMdbEnv* ev)
|
||||
{
|
||||
morkEnv *mev = morkEnv::FromMdbEnv(ev);
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
|
||||
{
|
||||
if ( mStream_Dirty )
|
||||
this->spill_buf(mev);
|
||||
|
||||
rv = file->Flush(ev);
|
||||
}
|
||||
else this->NewFileDownError(mev);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
// protected: // protected non-poly morkStream methods (for char io)
|
||||
|
||||
int
|
||||
morkStream::fill_getc(morkEnv* ev)
|
||||
{
|
||||
int c = EOF;
|
||||
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenAndActiveFile() && file )
|
||||
{
|
||||
mork_u1* buf = mStream_Buf;
|
||||
mork_u1* end = mStream_ReadEnd; // beyond buf after earlier read
|
||||
if ( end > buf ) // any earlier read bytes buffered?
|
||||
{
|
||||
mStream_BufPos += ( end - buf ); // advance past old read
|
||||
}
|
||||
|
||||
if ( ev->Good() ) // no errors yet?
|
||||
{
|
||||
// file->Seek(ev, mStream_BufPos); // set file pos
|
||||
// if ( ev->Good() ) // no seek error?
|
||||
// {
|
||||
// }
|
||||
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
mork_num actual = 0;
|
||||
file->Get(menv, buf, mStream_BufSize, mStream_BufPos, &actual);
|
||||
if ( ev->Good() ) // no read errors?
|
||||
{
|
||||
if ( actual > mStream_BufSize ) // more than asked for??
|
||||
actual = mStream_BufSize;
|
||||
|
||||
mStream_At = buf;
|
||||
mStream_ReadEnd = buf + actual;
|
||||
if ( actual ) // any bytes actually read?
|
||||
{
|
||||
c = *mStream_At++; // return first byte from buffer
|
||||
mStream_HitEof = morkBool_kFalse;
|
||||
}
|
||||
else
|
||||
mStream_HitEof = morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
morkStream::spill_putc(morkEnv* ev, int c)
|
||||
{
|
||||
this->spill_buf(ev);
|
||||
if ( ev->Good() && mStream_At < mStream_WriteEnd )
|
||||
this->Putc(ev, c);
|
||||
}
|
||||
|
||||
void
|
||||
morkStream::spill_buf(morkEnv* ev) // spill/flush from buffer to file
|
||||
{
|
||||
nsIMdbFile* file = mStream_ContentFile;
|
||||
if ( this->IsOpenOrClosingNode() && this->FileActive() && file )
|
||||
{
|
||||
mork_u1* buf = mStream_Buf;
|
||||
if ( mStream_Dirty )
|
||||
{
|
||||
mork_u1* at = mStream_At;
|
||||
if ( at >= buf && at <= mStream_WriteEnd ) // order?
|
||||
{
|
||||
mork_num count = (mork_num) (at - buf); // bytes buffered
|
||||
if ( count ) // anything to write to the string?
|
||||
{
|
||||
if ( count > mStream_BufSize ) // no more than max?
|
||||
{
|
||||
count = mStream_BufSize;
|
||||
mStream_WriteEnd = buf + mStream_BufSize;
|
||||
this->NewBadCursorSlotsError(ev);
|
||||
}
|
||||
if ( ev->Good() )
|
||||
{
|
||||
// file->Seek(ev, mStream_BufPos);
|
||||
// if ( ev->Good() )
|
||||
// {
|
||||
// }
|
||||
nsIMdbEnv* menv = ev->AsMdbEnv();
|
||||
mork_num actual = 0;
|
||||
|
||||
file->Put(menv, buf, count, mStream_BufPos, &actual);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
mStream_BufPos += actual; // past bytes written
|
||||
mStream_At = buf; // reset buffer cursor
|
||||
mStream_Dirty = morkBool_kFalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else this->NewBadCursorOrderError(ev);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MORK_DEBUG
|
||||
ev->NewWarning("stream:spill:not:dirty");
|
||||
#endif /*MORK_DEBUG*/
|
||||
}
|
||||
}
|
||||
else this->NewFileDownError(ev);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,251 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKSTREAM_
|
||||
#define _MORKSTREAM_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKFILE_
|
||||
#include "morkFile.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*=============================================================================
|
||||
* morkStream: buffered file i/o
|
||||
*/
|
||||
|
||||
/*| morkStream exists to define an morkFile subclass that provides buffered
|
||||
**| i/o for an underlying content file. Naturally this arrangement only makes
|
||||
**| sense when the underlying content file is itself not efficiently buffered
|
||||
**| (especially for character by character i/o).
|
||||
**|
|
||||
**|| morkStream is intended for either reading use or writing use, but not
|
||||
**| both simultaneously or interleaved. Pick one when the stream is created
|
||||
**| and don't change your mind. This restriction is intended to avoid obscure
|
||||
**| and complex bugs that might arise from interleaved reads and writes -- so
|
||||
**| just don't do it. A stream is either a sink or a source, but not both.
|
||||
**|
|
||||
**|| (When the underlying content file is intended to support both reading and
|
||||
**| writing, a developer might use two instances of morkStream where one is for
|
||||
**| reading and the other is for writing. In this case, a developer must take
|
||||
**| care to keep the two streams in sync because each will maintain a separate
|
||||
**| buffer representing a cache consistency problem for the other. A simple
|
||||
**| approach is to invalidate the buffer of one when one uses the other, with
|
||||
**| the assumption that closely mixed reading and writing is not expected, so
|
||||
**| that little cost is associated with changing read/write streaming modes.)
|
||||
**|
|
||||
**|| Exactly one of mStream_ReadEnd or mStream_WriteEnd must be a null pointer,
|
||||
**| and this will cause the right thing to occur when inlines use them, because
|
||||
**| mStream_At < mStream_WriteEnd (for example) will always be false and the
|
||||
**| else branch of the statement calls a function that raises an appropriate
|
||||
**| error to complain about either reading a sink or writing a source.
|
||||
**|
|
||||
**|| morkStream is a direct clone of ab_Stream from Communicator 4.5's
|
||||
**| address book code, which in turn was based on the stream class in the
|
||||
**| public domain Mithril programming language.
|
||||
|*/
|
||||
|
||||
#define morkStream_kPrintBufSize /*i*/ 512 /* buffer size used by printf() */
|
||||
|
||||
#define morkStream_kMinBufSize /*i*/ 512 /* buffer no fewer bytes */
|
||||
#define morkStream_kMaxBufSize /*i*/ (32 * 1024) /* buffer no more bytes */
|
||||
|
||||
#define morkDerived_kStream /*i*/ 0x7A74 /* ascii 'zt' */
|
||||
|
||||
class morkStream /*d*/ : public morkFile { /* from Mithril's AgStream class */
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected morkStream members
|
||||
mork_u1* mStream_At; // pointer into mStream_Buf
|
||||
mork_u1* mStream_ReadEnd; // null or one byte past last readable byte
|
||||
mork_u1* mStream_WriteEnd; // null or mStream_Buf + mStream_BufSize
|
||||
|
||||
nsIMdbFile* mStream_ContentFile; // where content is read and written
|
||||
|
||||
mork_u1* mStream_Buf; // dynamically allocated memory to buffer io
|
||||
mork_size mStream_BufSize; // requested buf size (fixed by min and max)
|
||||
mork_pos mStream_BufPos; // logical position of byte at mStream_Buf
|
||||
mork_bool mStream_Dirty; // does the buffer need to be flushed?
|
||||
mork_bool mStream_HitEof; // has eof been reached? (only frozen streams)
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseStream() only if open
|
||||
virtual ~morkStream(); // assert that CloseStream() executed earlier
|
||||
|
||||
public: // morkStream construction & destruction
|
||||
morkStream(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbFile* ioContentFile, mork_size inBufSize, mork_bool inFrozen);
|
||||
void CloseStream(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkStream(const morkStream& other);
|
||||
morkStream& operator=(const morkStream& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsStream() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kStream; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
void NonStreamTypeError(morkEnv* ev);
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // virtual morkFile methods
|
||||
|
||||
NS_IMETHOD Steal(nsIMdbEnv* ev, nsIMdbFile* ioThief);
|
||||
// Steal: tell this file to close any associated i/o stream in the file
|
||||
// system, because the file ioThief intends to reopen the file in order
|
||||
// to provide the MDB implementation with more exotic file access than is
|
||||
// offered by the nsIMdbFile alone. Presumably the thief knows enough
|
||||
// from Path() in order to know which file to reopen. If Steal() is
|
||||
// successful, this file should probably delegate all future calls to
|
||||
// the nsIMdbFile interface down to the thief files, so that even after
|
||||
// the file has been stolen, it can still be read, written, or forcibly
|
||||
// closed (by a call to CloseMdbObject()).
|
||||
|
||||
NS_IMETHOD BecomeTrunk(nsIMdbEnv* ev);
|
||||
// If this file is a file version branch created by calling AcquireBud(),
|
||||
// BecomeTrunk() causes this file's content to replace the original
|
||||
// file's content, typically by assuming the original file's identity.
|
||||
|
||||
NS_IMETHOD AcquireBud(nsIMdbEnv* ev, nsIMdbHeap* ioHeap, nsIMdbFile** acqBud);
|
||||
// AcquireBud() starts a new "branch" version of the file, empty of content,
|
||||
// so that a new version of the file can be written. This new file
|
||||
// can later be told to BecomeTrunk() the original file, so the branch
|
||||
// created by budding the file will replace the original file. Some
|
||||
// file subclasses might initially take the unsafe but expedient
|
||||
// approach of simply truncating this file down to zero length, and
|
||||
// then returning the same morkFile pointer as this, with an extra
|
||||
// reference count increment. Note that the caller of AcquireBud() is
|
||||
// expected to eventually call CutStrongRef() on the returned file
|
||||
// in order to release the strong reference. High quality versions
|
||||
// of morkFile subclasses will create entirely new files which later
|
||||
// are renamed to become the old file, so that better transactional
|
||||
// behavior is exhibited by the file, so crashes protect old files.
|
||||
// Note that AcquireBud() is an illegal operation on readonly files.
|
||||
|
||||
virtual mork_pos Length(morkEnv* ev) const; // eof
|
||||
NS_IMETHOD Tell(nsIMdbEnv* ev, mork_pos *aOutPos ) const;
|
||||
NS_IMETHOD Read(nsIMdbEnv* ev, void* outBuf, mork_size inSize, mork_size *aOutCount);
|
||||
NS_IMETHOD Seek(nsIMdbEnv* ev, mork_pos inPos, mork_pos *aOutPos);
|
||||
NS_IMETHOD Write(nsIMdbEnv* ev, const void* inBuf, mork_size inSize, mork_size *aOutCount);
|
||||
NS_IMETHOD Flush(nsIMdbEnv* ev);
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
protected: // protected non-poly morkStream methods (for char io)
|
||||
|
||||
int fill_getc(morkEnv* ev);
|
||||
void spill_putc(morkEnv* ev, int c);
|
||||
void spill_buf(morkEnv* ev); // spill/flush from buffer to file
|
||||
|
||||
// ````` ````` ````` ````` ````` ````` ````` `````
|
||||
public: // public non-poly morkStream methods
|
||||
|
||||
void NewBadCursorSlotsError(morkEnv* ev) const;
|
||||
void NewBadCursorOrderError(morkEnv* ev) const;
|
||||
void NewNullStreamBufferError(morkEnv* ev) const;
|
||||
void NewCantReadSinkError(morkEnv* ev) const;
|
||||
void NewCantWriteSourceError(morkEnv* ev) const;
|
||||
void NewPosBeyondEofError(morkEnv* ev) const;
|
||||
|
||||
nsIMdbFile* GetStreamContentFile() const { return mStream_ContentFile; }
|
||||
mork_size GetStreamBufferSize() const { return mStream_BufSize; }
|
||||
|
||||
mork_size PutIndent(morkEnv* ev, mork_count inDepth);
|
||||
// PutIndent() puts a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
|
||||
mork_size PutByteThenIndent(morkEnv* ev, int inByte, mork_count inDepth);
|
||||
// PutByteThenIndent() puts the byte, then a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
|
||||
mork_size PutStringThenIndent(morkEnv* ev,
|
||||
const char* inString, mork_count inDepth);
|
||||
// PutStringThenIndent() puts the string, then a linebreak, and then
|
||||
// "indents" by inDepth, and returns the line length after indentation.
|
||||
|
||||
mork_size PutString(morkEnv* ev, const char* inString);
|
||||
// PutString() returns the length of the string written.
|
||||
|
||||
mork_size PutStringThenNewline(morkEnv* ev, const char* inString);
|
||||
// PutStringThenNewline() returns total number of bytes written.
|
||||
|
||||
mork_size PutByteThenNewline(morkEnv* ev, int inByte);
|
||||
// PutByteThenNewline() returns total number of bytes written.
|
||||
|
||||
// ````` ````` stdio type methods ````` `````
|
||||
void Ungetc(int c) /*i*/
|
||||
{ if ( mStream_At > mStream_Buf && c > 0 ) *--mStream_At = (mork_u1) c; }
|
||||
|
||||
// Note Getc() returns EOF consistently after any fill_getc() error occurs.
|
||||
int Getc(morkEnv* ev) /*i*/
|
||||
{ return ( mStream_At < mStream_ReadEnd )? *mStream_At++ : fill_getc(ev); }
|
||||
|
||||
void Putc(morkEnv* ev, int c) /*i*/
|
||||
{
|
||||
mStream_Dirty = morkBool_kTrue;
|
||||
if ( mStream_At < mStream_WriteEnd )
|
||||
*mStream_At++ = (mork_u1) c;
|
||||
else
|
||||
spill_putc(ev, c);
|
||||
}
|
||||
|
||||
mork_size PutLineBreak(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakStream(morkStream* me,
|
||||
morkEnv* ev, morkStream** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongStream(morkStream* me,
|
||||
morkEnv* ev, morkStream** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKSTREAM_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,753 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#define _MORKTABLE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKARRAY_
|
||||
#include "morkArray.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#include "morkRowMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODEMAP_
|
||||
#include "morkNodeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPROBEMAP_
|
||||
#include "morkProbeMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBEAD_
|
||||
#include "morkBead.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class nsIMdbTable;
|
||||
#define morkDerived_kTable /*i*/ 0x5462 /* ascii 'Tb' */
|
||||
|
||||
/*| kStartRowArraySize: starting physical size of array for mTable_RowArray.
|
||||
**| We want this number very small, so that a table containing exactly one
|
||||
**| row member will not pay too significantly in space overhead. But we want
|
||||
**| a number bigger than one, so there is some space for growth.
|
||||
|*/
|
||||
#define morkTable_kStartRowArraySize 3 /* modest starting size for array */
|
||||
|
||||
/*| kMakeRowMapThreshold: this is the number of rows in a table which causes
|
||||
**| a hash table (mTable_RowMap) to be lazily created for faster member row
|
||||
**| identification, during such operations as cuts and adds. This number must
|
||||
**| be small enough that linear searches are not bad for member counts less
|
||||
**| than this; but this number must also be large enough that creating a hash
|
||||
**| table does not increase the per-row space overhead by a big percentage.
|
||||
**| For speed, numbers on the order of ten to twenty are all fine; for space,
|
||||
**| I believe a number as small as ten will have too much space overhead.
|
||||
|*/
|
||||
#define morkTable_kMakeRowMapThreshold 17 /* when to build mTable_RowMap */
|
||||
|
||||
#define morkTable_kStartRowMapSlotCount 13
|
||||
#define morkTable_kMaxTableGcUses 0x0FF /* max for 8-bit unsigned int */
|
||||
|
||||
#define morkTable_kUniqueBit ((mork_u1) (1 << 0))
|
||||
#define morkTable_kVerboseBit ((mork_u1) (1 << 1))
|
||||
#define morkTable_kNotedBit ((mork_u1) (1 << 2)) /* space has change notes */
|
||||
#define morkTable_kRewriteBit ((mork_u1) (1 << 3)) /* must rewrite all rows */
|
||||
#define morkTable_kNewMetaBit ((mork_u1) (1 << 4)) /* new table meta row */
|
||||
|
||||
class morkTable : public morkObject, public morkLink, public nsIMdbTable {
|
||||
|
||||
// NOTE the morkLink base is for morkRowSpace::mRowSpace_TablesByPriority
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // bead color setter & getter replace obsolete member mTable_Id:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
mork_tid TableId() const { return mBead_Color; }
|
||||
void SetTableId(mork_tid inTid) { mBead_Color = inTid; }
|
||||
|
||||
// we override these so we use xpcom ref-counting semantics.
|
||||
virtual mork_refs AddStrongRef(morkEnv* ev);
|
||||
virtual mork_refs CutStrongRef(morkEnv* ev);
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
// { ===== begin nsIMdbCollection methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetSeed(nsIMdbEnv* ev,
|
||||
mdb_seed* outSeed); // member change count
|
||||
NS_IMETHOD GetCount(nsIMdbEnv* ev,
|
||||
mdb_count* outCount); // member count
|
||||
|
||||
NS_IMETHOD GetPort(nsIMdbEnv* ev,
|
||||
nsIMdbPort** acqPort); // collection container
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHOD GetCursor( // make a cursor starting iter at inMemberPos
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
|
||||
nsIMdbCursor** acqCursor); // acquire new cursor instance
|
||||
// } ----- end cursor methods -----
|
||||
|
||||
// { ----- begin ID methods -----
|
||||
NS_IMETHOD GetOid(nsIMdbEnv* ev,
|
||||
mdbOid* outOid); // read object identity
|
||||
NS_IMETHOD BecomeContent(nsIMdbEnv* ev,
|
||||
const mdbOid* inOid); // exchange content
|
||||
// } ----- end ID methods -----
|
||||
|
||||
// { ----- begin activity dropping methods -----
|
||||
NS_IMETHOD DropActivity( // tell collection usage no longer expected
|
||||
nsIMdbEnv* ev);
|
||||
// } ----- end activity dropping methods -----
|
||||
|
||||
// } ===== end nsIMdbCollection methods =====
|
||||
NS_IMETHOD SetTablePriority(nsIMdbEnv* ev, mdb_priority inPrio);
|
||||
NS_IMETHOD GetTablePriority(nsIMdbEnv* ev, mdb_priority* outPrio);
|
||||
|
||||
NS_IMETHOD GetTableBeVerbose(nsIMdbEnv* ev, mdb_bool* outBeVerbose);
|
||||
NS_IMETHOD SetTableBeVerbose(nsIMdbEnv* ev, mdb_bool inBeVerbose);
|
||||
|
||||
NS_IMETHOD GetTableIsUnique(nsIMdbEnv* ev, mdb_bool* outIsUnique);
|
||||
|
||||
NS_IMETHOD GetTableKind(nsIMdbEnv* ev, mdb_kind* outTableKind);
|
||||
NS_IMETHOD GetRowScope(nsIMdbEnv* ev, mdb_scope* outRowScope);
|
||||
|
||||
NS_IMETHOD GetMetaRow(
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
|
||||
mdbOid* outOid, // output meta row oid, can be nil to suppress output
|
||||
nsIMdbRow** acqRow); // acquire table's unique singleton meta row
|
||||
// The purpose of a meta row is to support the persistent recording of
|
||||
// meta info about a table as cells put into the distinguished meta row.
|
||||
// Each table has exactly one meta row, which is not considered a member
|
||||
// of the collection of rows inside the table. The only way to tell
|
||||
// whether a row is a meta row is by the fact that it is returned by this
|
||||
// GetMetaRow() method from some table. Otherwise nothing distinguishes
|
||||
// a meta row from any other row. A meta row can be used anyplace that
|
||||
// any other row can be used, and can even be put into other tables (or
|
||||
// the same table) as a table member, if this is useful for some reason.
|
||||
// The first attempt to access a table's meta row using GetMetaRow() will
|
||||
// cause the meta row to be created if it did not already exist. When the
|
||||
// meta row is created, it will have the row oid that was previously
|
||||
// requested for this table's meta row; or if no oid was ever explicitly
|
||||
// specified for this meta row, then a unique oid will be generated in
|
||||
// the row scope named "m" (so obviously MDB clients should not
|
||||
// manually allocate any row IDs from that special meta scope namespace).
|
||||
// The meta row oid can be specified either when the table is created, or
|
||||
// else the first time that GetMetaRow() is called, by passing a non-nil
|
||||
// pointer to an oid for parameter inOptionalMetaRowOid. The meta row's
|
||||
// actual oid is returned in outOid (if this is a non-nil pointer), and
|
||||
// it will be different from inOptionalMetaRowOid when the meta row was
|
||||
// already given a different oid earlier.
|
||||
// } ----- end meta attribute methods -----
|
||||
|
||||
|
||||
// { ----- begin cursor methods -----
|
||||
NS_IMETHOD GetTableRowCursor( // make a cursor, starting iteration at inRowPos
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inRowPos, // zero-based ordinal position of row in table
|
||||
nsIMdbTableRowCursor** acqCursor); // acquire new cursor instance
|
||||
// } ----- end row position methods -----
|
||||
|
||||
// { ----- begin row position methods -----
|
||||
NS_IMETHOD PosToOid( // get row member for a table position
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inRowPos, // zero-based ordinal position of row in table
|
||||
mdbOid* outOid); // row oid at the specified position
|
||||
|
||||
NS_IMETHOD OidToPos( // test for the table position of a row member
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // row to find in table
|
||||
mdb_pos* outPos); // zero-based ordinal position of row in table
|
||||
|
||||
NS_IMETHOD PosToRow( // test for the table position of a row member
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_pos inRowPos, // zero-based ordinal position of row in table
|
||||
nsIMdbRow** acqRow); // acquire row at table position inRowPos
|
||||
|
||||
NS_IMETHOD RowToPos( // test for the table position of a row member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow, // row to find in table
|
||||
mdb_pos* outPos); // zero-based ordinal position of row in table
|
||||
// } ----- end row position methods -----
|
||||
|
||||
// { ----- begin oid set methods -----
|
||||
NS_IMETHOD AddOid( // make sure the row with inOid is a table member
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid); // row to ensure membership in table
|
||||
|
||||
NS_IMETHOD HasOid( // test for the table position of a row member
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // row to find in table
|
||||
mdb_bool* outHasOid); // whether inOid is a member row
|
||||
|
||||
NS_IMETHOD CutOid( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid); // row to remove from table
|
||||
// } ----- end oid set methods -----
|
||||
|
||||
// { ----- begin row set methods -----
|
||||
NS_IMETHOD NewRow( // create a new row instance in table
|
||||
nsIMdbEnv* ev, // context
|
||||
mdbOid* ioOid, // please use minus one (unbound) rowId for db-assigned IDs
|
||||
nsIMdbRow** acqRow); // create new row
|
||||
|
||||
NS_IMETHOD AddRow( // make sure the row with inOid is a table member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow); // row to ensure membership in table
|
||||
|
||||
NS_IMETHOD HasRow( // test for the table position of a row member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow, // row to find in table
|
||||
mdb_bool* outHasRow); // whether row is a table member
|
||||
|
||||
NS_IMETHOD CutRow( // make sure the row with inOid is not a member
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow); // row to remove from table
|
||||
|
||||
NS_IMETHOD CutAllRows( // remove all rows from the table
|
||||
nsIMdbEnv* ev); // context
|
||||
// } ----- end row set methods -----
|
||||
|
||||
// { ----- begin hinting methods -----
|
||||
NS_IMETHOD SearchColumnsHint( // advise re future expected search cols
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbColumnSet* inColumnSet); // columns likely to be searched
|
||||
|
||||
NS_IMETHOD SortColumnsHint( // advise re future expected sort columns
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbColumnSet* inColumnSet); // columns for likely sort requests
|
||||
|
||||
NS_IMETHOD StartBatchChangeHint( // advise before many adds and cuts
|
||||
nsIMdbEnv* ev, // context
|
||||
const void* inLabel); // intend unique address to match end call
|
||||
// If batch starts nest by virtue of nesting calls in the stack, then
|
||||
// the address of a local variable makes a good batch start label that
|
||||
// can be used at batch end time, and such addresses remain unique.
|
||||
|
||||
NS_IMETHOD EndBatchChangeHint( // advise before many adds and cuts
|
||||
nsIMdbEnv* ev, // context
|
||||
const void* inLabel); // label matching start label
|
||||
// Suppose a table is maintaining one or many sort orders for a table,
|
||||
// so that every row added to the table must be inserted in each sort,
|
||||
// and every row cut must be removed from each sort. If a db client
|
||||
// intends to make many such changes before needing any information
|
||||
// about the order or positions of rows inside a table, then a client
|
||||
// might tell the table to start batch changes in order to disable
|
||||
// sorting of rows for the interim. Presumably a table will then do
|
||||
// a full sort of all rows at need when the batch changes end, or when
|
||||
// a surprise request occurs for row position during batch changes.
|
||||
// } ----- end hinting methods -----
|
||||
|
||||
// { ----- begin searching methods -----
|
||||
NS_IMETHOD FindRowMatches( // search variable number of sorted cols
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbYarn* inPrefix, // content to find as prefix in row's column cell
|
||||
nsIMdbTableRowCursor** acqCursor); // set of matching rows
|
||||
|
||||
NS_IMETHOD GetSearchColumns( // query columns used by FindRowMatches()
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_count* outCount, // context
|
||||
mdbColumnSet* outColSet); // caller supplied space to put columns
|
||||
// GetSearchColumns() returns the columns actually searched when the
|
||||
// FindRowMatches() method is called. No more than mColumnSet_Count
|
||||
// slots of mColumnSet_Columns will be written, since mColumnSet_Count
|
||||
// indicates how many slots are present in the column array. The
|
||||
// actual number of search column used by the table is returned in
|
||||
// the outCount parameter; if this number exceeds mColumnSet_Count,
|
||||
// then a caller needs a bigger array to read the entire column set.
|
||||
// The minimum of mColumnSet_Count and outCount is the number slots
|
||||
// in mColumnSet_Columns that were actually written by this method.
|
||||
//
|
||||
// Callers are expected to change this set of columns by calls to
|
||||
// nsIMdbTable::SearchColumnsHint() or SetSearchSorting(), or both.
|
||||
// } ----- end searching methods -----
|
||||
|
||||
// { ----- begin sorting methods -----
|
||||
// sorting: note all rows are assumed sorted by row ID as a secondary
|
||||
// sort following the primary column sort, when table rows are sorted.
|
||||
|
||||
NS_IMETHOD
|
||||
CanSortColumn( // query which column is currently used for sorting
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // column to query sorting potential
|
||||
mdb_bool* outCanSort); // whether the column can be sorted
|
||||
|
||||
NS_IMETHOD GetSorting( // view same table in particular sorting
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // requested new column for sorting table
|
||||
nsIMdbSorting** acqSorting); // acquire sorting for column
|
||||
|
||||
NS_IMETHOD SetSearchSorting( // use this sorting in FindRowMatches()
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // often same as nsIMdbSorting::GetSortColumn()
|
||||
nsIMdbSorting* ioSorting); // requested sorting for some column
|
||||
// SetSearchSorting() attempts to inform the table that ioSorting
|
||||
// should be used during calls to FindRowMatches() for searching
|
||||
// the column which is actually sorted by ioSorting. This method
|
||||
// is most useful in conjunction with nsIMdbSorting::SetCompare(),
|
||||
// because otherwise a caller would not be able to override the
|
||||
// comparison ordering method used during searchs. Note that some
|
||||
// database implementations might be unable to use an arbitrarily
|
||||
// specified sort order, either due to schema or runtime interface
|
||||
// constraints, in which case ioSorting might not actually be used.
|
||||
// Presumably ioSorting is an instance that was returned from some
|
||||
// earlier call to nsIMdbTable::GetSorting(). A caller can also
|
||||
// use nsIMdbTable::SearchColumnsHint() to specify desired change
|
||||
// in which columns are sorted and searched by FindRowMatches().
|
||||
//
|
||||
// A caller can pass a nil pointer for ioSorting to request that
|
||||
// column inColumn no longer be used at all by FindRowMatches().
|
||||
// But when ioSorting is non-nil, then inColumn should match the
|
||||
// column actually sorted by ioSorting; when these do not agree,
|
||||
// implementations are instructed to give precedence to the column
|
||||
// specified by ioSorting (so this means callers might just pass
|
||||
// zero for inColumn when ioSorting is also provided, since then
|
||||
// inColumn is both redundant and ignored).
|
||||
// } ----- end sorting methods -----
|
||||
|
||||
// { ----- begin moving methods -----
|
||||
// moving a row does nothing unless a table is currently unsorted
|
||||
|
||||
NS_IMETHOD MoveOid( // change position of row in unsorted table
|
||||
nsIMdbEnv* ev, // context
|
||||
const mdbOid* inOid, // row oid to find in table
|
||||
mdb_pos inHintFromPos, // suggested hint regarding start position
|
||||
mdb_pos inToPos, // desired new position for row inRowId
|
||||
mdb_pos* outActualPos); // actual new position of row in table
|
||||
|
||||
NS_IMETHOD MoveRow( // change position of row in unsorted table
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow* ioRow, // row oid to find in table
|
||||
mdb_pos inHintFromPos, // suggested hint regarding start position
|
||||
mdb_pos inToPos, // desired new position for row inRowId
|
||||
mdb_pos* outActualPos); // actual new position of row in table
|
||||
// } ----- end moving methods -----
|
||||
|
||||
// { ----- begin index methods -----
|
||||
NS_IMETHOD AddIndex( // create a sorting index for column if possible
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // the column to sort by index
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental index building
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the index addition will be finished.
|
||||
|
||||
NS_IMETHOD CutIndex( // stop supporting a specific column index
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // the column with index to be removed
|
||||
nsIMdbThumb** acqThumb); // acquire thumb for incremental index destroy
|
||||
// Call nsIMdbThumb::DoMore() until done, or until the thumb is broken, and
|
||||
// then the index removal will be finished.
|
||||
|
||||
NS_IMETHOD HasIndex( // query for current presence of a column index
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // the column to investigate
|
||||
mdb_bool* outHasIndex); // whether column has index for this column
|
||||
|
||||
|
||||
NS_IMETHOD EnableIndexOnSort( // create an index for col on first sort
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn); // the column to index if ever sorted
|
||||
|
||||
NS_IMETHOD QueryIndexOnSort( // check whether index on sort is enabled
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn, // the column to investigate
|
||||
mdb_bool* outIndexOnSort); // whether column has index-on-sort enabled
|
||||
|
||||
NS_IMETHOD DisableIndexOnSort( // prevent future index creation on sort
|
||||
nsIMdbEnv* ev, // context
|
||||
mdb_column inColumn); // the column to index if ever sorted
|
||||
// } ----- end index methods -----
|
||||
|
||||
morkStore* mTable_Store; // non-refcnted ptr to port
|
||||
|
||||
// mTable_RowSpace->SpaceScope() is row scope
|
||||
morkRowSpace* mTable_RowSpace; // non-refcnted ptr to containing space
|
||||
|
||||
morkRow* mTable_MetaRow; // table's actual meta row
|
||||
mdbOid mTable_MetaRowOid; // oid for meta row
|
||||
|
||||
morkRowMap* mTable_RowMap; // (strong ref) hash table of all members
|
||||
morkArray mTable_RowArray; // array of morkRow pointers
|
||||
|
||||
morkList mTable_ChangeList; // list of table changes
|
||||
mork_u2 mTable_ChangesCount; // length of changes list
|
||||
mork_u2 mTable_ChangesMax; // max list length before rewrite
|
||||
|
||||
// mork_tid mTable_Id;
|
||||
mork_kind mTable_Kind;
|
||||
|
||||
mork_u1 mTable_Flags; // bit flags
|
||||
mork_priority mTable_Priority; // 0..9, any other value equals 9
|
||||
mork_u1 mTable_GcUses; // persistent references from cells
|
||||
mork_u1 mTable_Pad; // for u4 alignment
|
||||
|
||||
public: // flags bit twiddling
|
||||
|
||||
void SetTableUnique() { mTable_Flags |= morkTable_kUniqueBit; }
|
||||
void SetTableVerbose() { mTable_Flags |= morkTable_kVerboseBit; }
|
||||
void SetTableNoted() { mTable_Flags |= morkTable_kNotedBit; }
|
||||
void SetTableRewrite() { mTable_Flags |= morkTable_kRewriteBit; }
|
||||
void SetTableNewMeta() { mTable_Flags |= morkTable_kNewMetaBit; }
|
||||
|
||||
void ClearTableUnique() { mTable_Flags &= (mork_u1) ~morkTable_kUniqueBit; }
|
||||
void ClearTableVerbose() { mTable_Flags &= (mork_u1) ~morkTable_kVerboseBit; }
|
||||
void ClearTableNoted() { mTable_Flags &= (mork_u1) ~morkTable_kNotedBit; }
|
||||
void ClearTableRewrite() { mTable_Flags &= (mork_u1) ~morkTable_kRewriteBit; }
|
||||
void ClearTableNewMeta() { mTable_Flags &= (mork_u1) ~morkTable_kNewMetaBit; }
|
||||
|
||||
mork_bool IsTableUnique() const
|
||||
{ return ( mTable_Flags & morkTable_kUniqueBit ) != 0; }
|
||||
|
||||
mork_bool IsTableVerbose() const
|
||||
{ return ( mTable_Flags & morkTable_kVerboseBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNoted() const
|
||||
{ return ( mTable_Flags & morkTable_kNotedBit ) != 0; }
|
||||
|
||||
mork_bool IsTableRewrite() const
|
||||
{ return ( mTable_Flags & morkTable_kRewriteBit ) != 0; }
|
||||
|
||||
mork_bool IsTableNewMeta() const
|
||||
{ return ( mTable_Flags & morkTable_kNewMetaBit ) != 0; }
|
||||
|
||||
public: // table dirty handling more complex than morkNode::SetNodeDirty() etc.
|
||||
|
||||
void SetTableDirty() { this->SetNodeDirty(); }
|
||||
void SetTableClean(morkEnv* ev);
|
||||
|
||||
mork_bool IsTableClean() const { return this->IsNodeClean(); }
|
||||
mork_bool IsTableDirty() const { return this->IsNodeDirty(); }
|
||||
|
||||
public: // morkNode memory management operators
|
||||
void* operator new(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev) CPP_THROW_NEW
|
||||
{ return morkNode::MakeNew(inSize, ioHeap, ev); }
|
||||
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseTable() if open
|
||||
virtual ~morkTable(); // assert that close executed earlier
|
||||
|
||||
public: // morkTable construction & destruction
|
||||
morkTable(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap, morkStore* ioStore,
|
||||
nsIMdbHeap* ioSlotHeap, morkRowSpace* ioRowSpace,
|
||||
const mdbOid* inOptionalMetaRowOid, // can be nil to avoid specifying
|
||||
mork_tid inTableId,
|
||||
mork_kind inKind, mork_bool inMustBeUnique);
|
||||
void CloseTable(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkTable(const morkTable& other);
|
||||
morkTable& operator=(const morkTable& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsTable() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kTable; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // errors
|
||||
static void NonTableTypeError(morkEnv* ev);
|
||||
static void NonTableTypeWarning(morkEnv* ev);
|
||||
static void NilRowSpaceError(morkEnv* ev);
|
||||
|
||||
public: // warnings
|
||||
static void TableGcUsesUnderflowWarning(morkEnv* ev);
|
||||
|
||||
public: // noting table changes
|
||||
|
||||
mork_bool HasChangeOverflow() const
|
||||
{ return mTable_ChangesCount >= mTable_ChangesMax; }
|
||||
|
||||
void NoteTableSetAll(morkEnv* ev);
|
||||
void NoteTableMoveRow(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
|
||||
void note_row_change(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
void note_row_move(morkEnv* ev, morkRow* ioRow, mork_pos inNewPos);
|
||||
|
||||
void NoteTableAddRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kAdd, ioRow); }
|
||||
|
||||
void NoteTableCutRow(morkEnv* ev, morkRow* ioRow)
|
||||
{ this->note_row_change(ev, morkChange_kCut, ioRow); }
|
||||
|
||||
protected: // internal row map methods
|
||||
|
||||
morkRow* find_member_row(morkEnv* ev, morkRow* ioRow);
|
||||
void build_row_map(morkEnv* ev);
|
||||
|
||||
public: // other table methods
|
||||
|
||||
mork_bool MaybeDirtySpaceStoreAndTable();
|
||||
|
||||
morkRow* GetMetaRow(morkEnv* ev, const mdbOid* inOptionalMetaRowOid);
|
||||
|
||||
mork_u2 AddTableGcUse(morkEnv* ev);
|
||||
mork_u2 CutTableGcUse(morkEnv* ev);
|
||||
|
||||
// void DirtyAllTableContent(morkEnv* ev);
|
||||
|
||||
mork_seed TableSeed() const { return mTable_RowArray.mArray_Seed; }
|
||||
|
||||
morkRow* SafeRowAt(morkEnv* ev, mork_pos inPos)
|
||||
{ return (morkRow*) mTable_RowArray.SafeAt(ev, inPos); }
|
||||
|
||||
nsIMdbTable* AcquireTableHandle(morkEnv* ev); // mObject_Handle
|
||||
|
||||
mork_count GetRowCount() const { return mTable_RowArray.mArray_Fill; }
|
||||
|
||||
mork_bool IsTableUsed() const
|
||||
{ return (mTable_GcUses != 0 || this->GetRowCount() != 0); }
|
||||
|
||||
void GetTableOid(morkEnv* ev, mdbOid* outOid);
|
||||
mork_pos ArrayHasOid(morkEnv* ev, const mdbOid* inOid);
|
||||
mork_bool MapHasOid(morkEnv* ev, const mdbOid* inOid);
|
||||
mork_bool AddRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutRow(morkEnv* ev, morkRow* ioRow); // returns ev->Good()
|
||||
mork_bool CutAllRows(morkEnv* ev); // returns ev->Good()
|
||||
|
||||
mork_pos MoveRow(morkEnv* ev, morkRow* ioRow, // change row position
|
||||
mork_pos inHintFromPos, // suggested hint regarding start position
|
||||
mork_pos inToPos); // desired new position for row ioRow
|
||||
// MoveRow() returns the actual position of ioRow afterwards; this
|
||||
// position is -1 if and only if ioRow was not found as a member.
|
||||
|
||||
|
||||
morkTableRowCursor* NewTableRowCursor(morkEnv* ev, mork_pos inRowPos);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakTable(morkTable* me,
|
||||
morkEnv* ev, morkTable** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongTable(morkTable* me,
|
||||
morkEnv* ev, morkTable** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// use negative values for kCut and kAdd, to keep non-neg move pos distinct:
|
||||
#define morkTableChange_kCut ((mork_pos) -1) /* shows row was cut */
|
||||
#define morkTableChange_kAdd ((mork_pos) -2) /* shows row was added */
|
||||
#define morkTableChange_kNone ((mork_pos) -3) /* unknown change */
|
||||
|
||||
class morkTableChange : public morkNext {
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkRow* mTableChange_Row; // the row in the change
|
||||
|
||||
mork_pos mTableChange_Pos; // kAdd, kCut, or non-neg for row move
|
||||
|
||||
public:
|
||||
morkTableChange(morkEnv* ev, mork_change inChange, morkRow* ioRow);
|
||||
// use this constructor for inChange == morkChange_kAdd or morkChange_kCut
|
||||
|
||||
morkTableChange(morkEnv* ev, morkRow* ioRow, mork_pos inPos);
|
||||
// use this constructor when the row is moved
|
||||
|
||||
public:
|
||||
void UnknownChangeError(morkEnv* ev) const; // morkChange_kAdd or morkChange_kCut
|
||||
void NegativeMovePosError(morkEnv* ev) const; // move must be non-neg position
|
||||
|
||||
public:
|
||||
|
||||
mork_bool IsAddRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kAdd ); }
|
||||
|
||||
mork_bool IsCutRowTableChange() const
|
||||
{ return ( mTableChange_Pos == morkTableChange_kCut ); }
|
||||
|
||||
mork_bool IsMoveRowTableChange() const
|
||||
{ return ( mTableChange_Pos >= 0 ); }
|
||||
|
||||
public:
|
||||
|
||||
mork_pos GetMovePos() const { return mTableChange_Pos; }
|
||||
// GetMovePos() assumes that IsMoveRowTableChange() is true.
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkDerived_kTableMap /*i*/ 0x744D /* ascii 'tM' */
|
||||
|
||||
/*| morkTableMap: maps mork_token -> morkTable
|
||||
|*/
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
class morkTableMap : public morkBeadMap {
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
class morkTableMap : public morkNodeMap { // for mapping tokens to tables
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
|
||||
public:
|
||||
|
||||
virtual ~morkTableMap();
|
||||
morkTableMap(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap);
|
||||
|
||||
public: // other map methods
|
||||
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
mork_bool AddTable(morkEnv* ev, morkTable* ioTable)
|
||||
{ return this->AddBead(ev, ioTable); }
|
||||
// the AddTable() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutTable(morkEnv* ev, mork_tid inTid)
|
||||
{ return this->CutBead(ev, inTid); }
|
||||
// The CutTable() boolean return indicates whether removal happened.
|
||||
|
||||
morkTable* GetTable(morkEnv* ev, mork_tid inTid)
|
||||
{ return (morkTable*) this->GetBead(ev, inTid); }
|
||||
// Note the returned table does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllTables(morkEnv* ev)
|
||||
{ return this->CutAllBeads(ev); }
|
||||
// CutAllTables() releases all the referenced table values.
|
||||
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
mork_bool AddTable(morkEnv* ev, morkTable* ioTable)
|
||||
{ return this->AddNode(ev, ioTable->TableId(), ioTable); }
|
||||
// the AddTable() boolean return equals ev->Good().
|
||||
|
||||
mork_bool CutTable(morkEnv* ev, mork_tid inTid)
|
||||
{ return this->CutNode(ev, inTid); }
|
||||
// The CutTable() boolean return indicates whether removal happened.
|
||||
|
||||
morkTable* GetTable(morkEnv* ev, mork_tid inTid)
|
||||
{ return (morkTable*) this->GetNode(ev, inTid); }
|
||||
// Note the returned table does NOT have an increase in refcount for this.
|
||||
|
||||
mork_num CutAllTables(morkEnv* ev)
|
||||
{ return this->CutAllNodes(ev); }
|
||||
// CutAllTables() releases all the referenced table values.
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
|
||||
};
|
||||
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
class morkTableMapIter: public morkBeadMapIter {
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
class morkTableMapIter: public morkMapIter{ // typesafe wrapper class
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
|
||||
public:
|
||||
|
||||
#ifdef MORK_BEAD_OVER_NODE_MAPS
|
||||
morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
|
||||
: morkBeadMapIter(ev, ioMap) { }
|
||||
|
||||
morkTableMapIter( ) : morkBeadMapIter() { }
|
||||
void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
|
||||
{ this->InitBeadMapIter(ev, ioMap); }
|
||||
|
||||
morkTable* FirstTable(morkEnv* ev)
|
||||
{ return (morkTable*) this->FirstBead(ev); }
|
||||
|
||||
morkTable* NextTable(morkEnv* ev)
|
||||
{ return (morkTable*) this->NextBead(ev); }
|
||||
|
||||
morkTable* HereTable(morkEnv* ev)
|
||||
{ return (morkTable*) this->HereBead(ev); }
|
||||
|
||||
|
||||
#else /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
morkTableMapIter(morkEnv* ev, morkTableMap* ioMap)
|
||||
: morkMapIter(ev, ioMap) { }
|
||||
|
||||
morkTableMapIter( ) : morkMapIter() { }
|
||||
void InitTableMapIter(morkEnv* ev, morkTableMap* ioMap)
|
||||
{ this->InitMapIter(ev, ioMap); }
|
||||
|
||||
mork_change*
|
||||
FirstTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->First(ev, outTid, outTable); }
|
||||
|
||||
mork_change*
|
||||
NextTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->Next(ev, outTid, outTable); }
|
||||
|
||||
mork_change*
|
||||
HereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->Here(ev, outTid, outTable); }
|
||||
|
||||
// cutting while iterating hash map might dirty the parent table:
|
||||
mork_change*
|
||||
CutHereTable(morkEnv* ev, mork_tid* outTid, morkTable** outTable)
|
||||
{ return this->CutHere(ev, outTid, outTable); }
|
||||
#endif /*MORK_BEAD_OVER_NODE_MAPS*/
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKTABLE_ */
|
||||
|
|
@ -0,0 +1,531 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Blake Ross (blake@blakeross.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLEROWCURSOR_
|
||||
#include "morkTableRowCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#include "morkTable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROW_
|
||||
#include "morkRow.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkTableRowCursor::CloseMorkNode(morkEnv* ev) // CloseTableRowCursor() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseTableRowCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkTableRowCursor::~morkTableRowCursor() // CloseTableRowCursor() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkTableRowCursor::morkTableRowCursor(morkEnv* ev,
|
||||
const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos)
|
||||
: morkCursor(ev, inUsage, ioHeap)
|
||||
, mTableRowCursor_Table( 0 )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioTable )
|
||||
{
|
||||
mCursor_Pos = inRowPos;
|
||||
mCursor_Seed = ioTable->TableSeed();
|
||||
morkTable::SlotWeakTable(ioTable, ev, &mTableRowCursor_Table);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kTableRowCursor;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkTableRowCursor, morkCursor, nsIMdbTableRowCursor)
|
||||
/*public non-poly*/ void
|
||||
morkTableRowCursor::CloseTableRowCursor(morkEnv* ev)
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mCursor_Pos = -1;
|
||||
mCursor_Seed = 0;
|
||||
morkTable::SlotWeakTable((morkTable*) 0, ev, &mTableRowCursor_Table);
|
||||
this->CloseCursor(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ----- begin attribute methods -----
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::GetCount(nsIMdbEnv* mev, mdb_count* outCount)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_count count = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
count = GetMemberCount(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outCount )
|
||||
*outCount = count;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed)
|
||||
{
|
||||
NS_ASSERTION(PR_FALSE, "not implemented");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::SetPos(nsIMdbEnv* mev, mdb_pos inPos)
|
||||
{
|
||||
mCursor_Pos = inPos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::GetPos(nsIMdbEnv* mev, mdb_pos* outPos)
|
||||
{
|
||||
*outPos = mCursor_Pos;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::SetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool inFail)
|
||||
{
|
||||
mCursor_DoFailOnSeedOutOfSync = inFail;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkTableRowCursor::GetDoFailOnSeedOutOfSync(nsIMdbEnv* mev, mdb_bool* outFail)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(outFail);
|
||||
*outFail = mCursor_DoFailOnSeedOutOfSync;
|
||||
return NS_OK;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
|
||||
// { ===== begin nsIMdbTableRowCursor methods =====
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::GetTable(nsIMdbEnv* mev, nsIMdbTable** acqTable)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbTable* outTable = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( mTableRowCursor_Table )
|
||||
outTable = mTableRowCursor_Table->AcquireTableHandle(ev);
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqTable )
|
||||
*acqTable = outTable;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin oid iteration methods -----
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::NextRowOid( // get row id of next row in the table
|
||||
nsIMdbEnv* mev, // context
|
||||
mdbOid* outOid, // out row oid
|
||||
mdb_pos* outRowPos)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_pos pos = -1;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( outOid )
|
||||
{
|
||||
pos = NextRowOid(ev, outOid);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outRowPos )
|
||||
*outRowPos = pos;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::PrevRowOid( // get row id of previous row in the table
|
||||
nsIMdbEnv* mev, // context
|
||||
mdbOid* outOid, // out row oid
|
||||
mdb_pos* outRowPos)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mork_pos pos = -1;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
if ( outOid )
|
||||
{
|
||||
pos = PrevRowOid(ev, outOid);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outRowPos )
|
||||
*outRowPos = pos;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end oid iteration methods -----
|
||||
|
||||
// { ----- begin row iteration methods -----
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::NextRow( // get row cells from table for cells already in row
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow** acqRow, // acquire next row in table
|
||||
mdb_pos* outRowPos)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbRow* outRow = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
|
||||
mdbOid oid; // place to put oid we intend to ignore
|
||||
morkRow* row = NextRow(ev, &oid, outRowPos);
|
||||
if ( row )
|
||||
{
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
outRow = row->AcquireRowHandle(ev, store);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqRow )
|
||||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::PrevRow( // get row cells from table for cells already in row
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbRow** acqRow, // acquire previous row in table
|
||||
mdb_pos* outRowPos)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbRow* outRow = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
|
||||
mdbOid oid; // place to put oid we intend to ignore
|
||||
morkRow* row = PrevRow(ev, &oid, outRowPos);
|
||||
if ( row )
|
||||
{
|
||||
morkStore* store = row->GetRowSpaceStore(ev);
|
||||
if ( store )
|
||||
outRow = row->AcquireRowHandle(ev, store);
|
||||
}
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqRow )
|
||||
*acqRow = outRow;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
// } ----- end row iteration methods -----
|
||||
|
||||
|
||||
// { ----- begin duplicate row removal methods -----
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::CanHaveDupRowMembers(nsIMdbEnv* mev, // cursor might hold dups?
|
||||
mdb_bool* outCanHaveDups)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
mdb_bool canHaveDups = mdbBool_kFalse;
|
||||
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
canHaveDups = CanHaveDupRowMembers(ev);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( outCanHaveDups )
|
||||
*outCanHaveDups = canHaveDups;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkTableRowCursor::MakeUniqueCursor( // clone cursor, removing duplicate rows
|
||||
nsIMdbEnv* mev, // context
|
||||
nsIMdbTableRowCursor** acqCursor) // acquire clone with no dups
|
||||
// Note that MakeUniqueCursor() is never necessary for a cursor which was
|
||||
// created by table method nsIMdbTable::GetTableRowCursor(), because a table
|
||||
// never contains the same row as a member more than once. However, a cursor
|
||||
// created by table method nsIMdbTable::FindRowMatches() might contain the
|
||||
// same row more than once, because the same row can generate a hit by more
|
||||
// than one column with a matching string prefix. Note this method can
|
||||
// return the very same cursor instance with just an incremented refcount,
|
||||
// when the original cursor could not contain any duplicate rows (calling
|
||||
// CanHaveDupRowMembers() shows this case on a false return). Otherwise
|
||||
// this method returns a different cursor instance. Callers should not use
|
||||
// this MakeUniqueCursor() method lightly, because it tends to defeat the
|
||||
// purpose of lazy programming techniques, since it can force creation of
|
||||
// an explicit row collection in a new cursor's representation, in order to
|
||||
// inspect the row membership and remove any duplicates; this can have big
|
||||
// impact if a collection holds tens of thousands of rows or more, when
|
||||
// the original cursor with dups simply referenced rows indirectly by row
|
||||
// position ranges, without using an explicit row set representation.
|
||||
// Callers are encouraged to use nsIMdbCursor::GetCount() to determine
|
||||
// whether the row collection is very large (tens of thousands), and to
|
||||
// delay calling MakeUniqueCursor() when possible, until a user interface
|
||||
// element actually demands the creation of an explicit set representation.
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
nsIMdbTableRowCursor* outCursor = 0;
|
||||
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
AddRef();
|
||||
outCursor = this;
|
||||
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
if ( acqCursor )
|
||||
*acqCursor = outCursor;
|
||||
return outErr;
|
||||
}
|
||||
// } ----- end duplicate row removal methods -----
|
||||
|
||||
// } ===== end nsIMdbTableRowCursor methods =====
|
||||
|
||||
|
||||
/*static*/ void
|
||||
morkTableRowCursor::NonTableRowCursorTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkTableRowCursor");
|
||||
}
|
||||
|
||||
|
||||
mdb_pos
|
||||
morkTableRowCursor::NextRowOid(morkEnv* ev, mdbOid* outOid)
|
||||
{
|
||||
mdb_pos outPos = -1;
|
||||
(void) this->NextRow(ev, outOid, &outPos);
|
||||
return outPos;
|
||||
}
|
||||
|
||||
mdb_pos
|
||||
morkTableRowCursor::PrevRowOid(morkEnv* ev, mdbOid* outOid)
|
||||
{
|
||||
mdb_pos outPos = -1;
|
||||
(void) this->PrevRow(ev, outOid, &outPos);
|
||||
return outPos;
|
||||
}
|
||||
|
||||
mork_bool
|
||||
morkTableRowCursor::CanHaveDupRowMembers(morkEnv* ev)
|
||||
{
|
||||
return morkBool_kFalse; // false default is correct
|
||||
}
|
||||
|
||||
mork_count
|
||||
morkTableRowCursor::GetMemberCount(morkEnv* ev)
|
||||
{
|
||||
morkTable* table = mTableRowCursor_Table;
|
||||
if ( table )
|
||||
return table->mTable_RowArray.mArray_Fill;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkTableRowCursor::PrevRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos)
|
||||
{
|
||||
morkRow* outRow = 0;
|
||||
mork_pos pos = -1;
|
||||
|
||||
morkTable* table = mTableRowCursor_Table;
|
||||
if ( table )
|
||||
{
|
||||
if ( table->IsOpenNode() )
|
||||
{
|
||||
morkArray* array = &table->mTable_RowArray;
|
||||
pos = mCursor_Pos - 1;
|
||||
|
||||
if ( pos >= 0 && pos < (mork_pos)(array->mArray_Fill) )
|
||||
{
|
||||
mCursor_Pos = pos; // update for next time
|
||||
morkRow* row = (morkRow*) array->At(pos);
|
||||
if ( row )
|
||||
{
|
||||
if ( row->IsRow() )
|
||||
{
|
||||
outRow = row;
|
||||
*outOid = row->mRow_Oid;
|
||||
}
|
||||
else
|
||||
row->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
else
|
||||
{
|
||||
outOid->mOid_Scope = 0;
|
||||
outOid->mOid_Id = morkId_kMinusOne;
|
||||
}
|
||||
}
|
||||
else
|
||||
table->NonOpenNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
*outPos = pos;
|
||||
return outRow;
|
||||
}
|
||||
|
||||
morkRow*
|
||||
morkTableRowCursor::NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos)
|
||||
{
|
||||
morkRow* outRow = 0;
|
||||
mork_pos pos = -1;
|
||||
|
||||
morkTable* table = mTableRowCursor_Table;
|
||||
if ( table )
|
||||
{
|
||||
if ( table->IsOpenNode() )
|
||||
{
|
||||
morkArray* array = &table->mTable_RowArray;
|
||||
pos = mCursor_Pos;
|
||||
if ( pos < 0 )
|
||||
pos = 0;
|
||||
else
|
||||
++pos;
|
||||
|
||||
if ( pos < (mork_pos)(array->mArray_Fill) )
|
||||
{
|
||||
mCursor_Pos = pos; // update for next time
|
||||
morkRow* row = (morkRow*) array->At(pos);
|
||||
if ( row )
|
||||
{
|
||||
if ( row->IsRow() )
|
||||
{
|
||||
outRow = row;
|
||||
*outOid = row->mRow_Oid;
|
||||
}
|
||||
else
|
||||
row->NonRowTypeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
else
|
||||
{
|
||||
outOid->mOid_Scope = 0;
|
||||
outOid->mOid_Id = morkId_kMinusOne;
|
||||
}
|
||||
}
|
||||
else
|
||||
table->NonOpenNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
*outPos = pos;
|
||||
return outRow;
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Blake Ross (blake@blakeross.com)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKTABLEROWCURSOR_
|
||||
#define _MORKTABLEROWCURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class orkinTableRowCursor;
|
||||
#define morkDerived_kTableRowCursor /*i*/ 0x7243 /* ascii 'rC' */
|
||||
|
||||
class morkTableRowCursor : public morkCursor, public nsIMdbTableRowCursor { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkFactory* mObject_Factory; // weak ref to suite factory
|
||||
|
||||
// mork_seed mCursor_Seed;
|
||||
// mork_pos mCursor_Pos;
|
||||
// mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
// mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
morkTable* mTableRowCursor_Table; // weak ref to table
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseTableRowCursor()
|
||||
virtual ~morkTableRowCursor(); // assert that close executed earlier
|
||||
|
||||
public: // morkTableRowCursor construction & destruction
|
||||
morkTableRowCursor(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos);
|
||||
void CloseTableRowCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkTableRowCursor(const morkTableRowCursor& other);
|
||||
morkTableRowCursor& operator=(const morkTableRowCursor& other);
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// { ----- begin attribute methods -----
|
||||
NS_IMETHOD GetCount(nsIMdbEnv* ev, mdb_count* outCount); // readonly
|
||||
NS_IMETHOD GetSeed(nsIMdbEnv* ev, mdb_seed* outSeed); // readonly
|
||||
|
||||
NS_IMETHOD SetPos(nsIMdbEnv* ev, mdb_pos inPos); // mutable
|
||||
NS_IMETHOD GetPos(nsIMdbEnv* ev, mdb_pos* outPos);
|
||||
|
||||
NS_IMETHOD SetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool inFail);
|
||||
NS_IMETHOD GetDoFailOnSeedOutOfSync(nsIMdbEnv* ev, mdb_bool* outFail);
|
||||
|
||||
// } ----- end attribute methods -----
|
||||
NS_IMETHOD GetTable(nsIMdbEnv* ev, nsIMdbTable** acqTable);
|
||||
// } ----- end attribute methods -----
|
||||
|
||||
// { ----- begin duplicate row removal methods -----
|
||||
NS_IMETHOD CanHaveDupRowMembers(nsIMdbEnv* ev, // cursor might hold dups?
|
||||
mdb_bool* outCanHaveDups);
|
||||
|
||||
NS_IMETHOD MakeUniqueCursor( // clone cursor, removing duplicate rows
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbTableRowCursor** acqCursor); // acquire clone with no dups
|
||||
// } ----- end duplicate row removal methods -----
|
||||
|
||||
// { ----- begin oid iteration methods -----
|
||||
NS_IMETHOD NextRowOid( // get row id of next row in the table
|
||||
nsIMdbEnv* ev, // context
|
||||
mdbOid* outOid, // out row oid
|
||||
mdb_pos* outRowPos); // zero-based position of the row in table
|
||||
NS_IMETHOD PrevRowOid( // get row id of previous row in the table
|
||||
nsIMdbEnv* ev, // context
|
||||
mdbOid* outOid, // out row oid
|
||||
mdb_pos* outRowPos); // zero-based position of the row in table
|
||||
// } ----- end oid iteration methods -----
|
||||
|
||||
// { ----- begin row iteration methods -----
|
||||
NS_IMETHOD NextRow( // get row cells from table for cells already in row
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow** acqRow, // acquire next row in table
|
||||
mdb_pos* outRowPos); // zero-based position of the row in table
|
||||
NS_IMETHOD PrevRow( // get row cells from table for cells already in row
|
||||
nsIMdbEnv* ev, // context
|
||||
nsIMdbRow** acqRow, // acquire previous row in table
|
||||
mdb_pos* outRowPos); // zero-based position of the row in table
|
||||
// } ----- end row iteration methods -----
|
||||
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsTableRowCursor() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kTableRowCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonTableRowCursorTypeError(morkEnv* ev);
|
||||
|
||||
public: // oid only iteration
|
||||
mdb_pos NextRowOid(morkEnv* ev, mdbOid* outOid);
|
||||
mdb_pos PrevRowOid(morkEnv* ev, mdbOid* outOid);
|
||||
|
||||
public: // other table row cursor methods
|
||||
|
||||
virtual mork_bool CanHaveDupRowMembers(morkEnv* ev);
|
||||
virtual mork_count GetMemberCount(morkEnv* ev);
|
||||
|
||||
virtual morkRow* NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos);
|
||||
virtual morkRow* PrevRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakTableRowCursor(morkTableRowCursor* me,
|
||||
morkEnv* ev, morkTableRowCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongTableRowCursor(morkTableRowCursor* me,
|
||||
morkEnv* ev, morkTableRowCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKTABLEROWCURSOR_ */
|
|
@ -0,0 +1,560 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTHUMB_
|
||||
#include "morkThumb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTORE_
|
||||
#include "morkStore.h"
|
||||
#endif
|
||||
|
||||
// #ifndef _MORKFILE_
|
||||
// #include "morkFile.h"
|
||||
// #endif
|
||||
|
||||
#ifndef _MORKWRITER_
|
||||
#include "morkWriter.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKPARSER_
|
||||
#include "morkParser.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKBUILDER_
|
||||
#include "morkBuilder.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkThumb::CloseMorkNode(morkEnv* ev) // CloseThumb() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseThumb(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkThumb::~morkThumb() // assert CloseThumb() executed earlier
|
||||
{
|
||||
CloseMorkNode(mMorkEnv);
|
||||
MORK_ASSERT(mThumb_Magic==0);
|
||||
MORK_ASSERT(mThumb_Store==0);
|
||||
MORK_ASSERT(mThumb_File==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkThumb::morkThumb(morkEnv* ev,
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap,
|
||||
nsIMdbHeap* ioSlotHeap, mork_magic inMagic)
|
||||
: morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*) 0)
|
||||
, mThumb_Magic( 0 )
|
||||
, mThumb_Total( 0 )
|
||||
, mThumb_Current( 0 )
|
||||
|
||||
, mThumb_Done( morkBool_kFalse )
|
||||
, mThumb_Broken( morkBool_kFalse )
|
||||
, mThumb_Seed( 0 )
|
||||
|
||||
, mThumb_Store( 0 )
|
||||
, mThumb_File( 0 )
|
||||
, mThumb_Writer( 0 )
|
||||
, mThumb_Builder( 0 )
|
||||
, mThumb_SourcePort( 0 )
|
||||
|
||||
, mThumb_DoCollect( morkBool_kFalse )
|
||||
{
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioSlotHeap )
|
||||
{
|
||||
mThumb_Magic = inMagic;
|
||||
mNode_Derived = morkDerived_kThumb;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED1(morkThumb, morkObject, nsIMdbThumb)
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkThumb::CloseThumb(morkEnv* ev) // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
mThumb_Magic = 0;
|
||||
if ( mThumb_Builder && mThumb_Store )
|
||||
mThumb_Store->ForgetBuilder(ev);
|
||||
morkBuilder::SlotStrongBuilder((morkBuilder*) 0, ev, &mThumb_Builder);
|
||||
|
||||
morkWriter::SlotStrongWriter((morkWriter*) 0, ev, &mThumb_Writer);
|
||||
nsIMdbFile_SlotStrongFile((nsIMdbFile*) 0, ev, &mThumb_File);
|
||||
morkStore::SlotStrongStore((morkStore*) 0, ev, &mThumb_Store);
|
||||
morkStore::SlotStrongPort((morkPort*) 0, ev, &mThumb_SourcePort);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
// { ===== begin nsIMdbThumb methods =====
|
||||
NS_IMETHODIMP
|
||||
morkThumb::GetProgress(nsIMdbEnv* mev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
GetProgress(ev, outTotal, outCurrent, outDone, outBroken);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkThumb::DoMore(nsIMdbEnv* mev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
DoMore(ev, outTotal, outCurrent, outDone, outBroken);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
morkThumb::CancelAndBreakThumb(nsIMdbEnv* mev)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
mThumb_Done = morkBool_kTrue;
|
||||
mThumb_Broken = morkBool_kTrue;
|
||||
CloseMorkNode(ev); // should I close this here?
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
return outErr;
|
||||
}
|
||||
// } ===== end nsIMdbThumb methods =====
|
||||
|
||||
/*static*/ void morkThumb::NonThumbTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkThumb");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::UnsupportedThumbMagicError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("unsupported mThumb_Magic");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::NilThumbStoreError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mThumb_Store");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::NilThumbFileError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mThumb_File");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::NilThumbWriterError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mThumb_Writer");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::NilThumbBuilderError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mThumb_Builder");
|
||||
}
|
||||
|
||||
/*static*/ void morkThumb::NilThumbSourcePortError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mThumb_SourcePort");
|
||||
}
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_OpenFileStore(morkEnv* ev, nsIMdbHeap* ioHeap,
|
||||
morkStore* ioStore)
|
||||
{
|
||||
morkThumb* outThumb = 0;
|
||||
if ( ioHeap && ioStore )
|
||||
{
|
||||
nsIMdbFile* file = ioStore->mStore_File;
|
||||
if ( file )
|
||||
{
|
||||
mork_pos fileEof = 0;
|
||||
file->Eof(ev->AsMdbEnv(), &fileEof);
|
||||
if ( ev->Good() )
|
||||
{
|
||||
outThumb = new(*ioHeap, ev)
|
||||
morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap,
|
||||
morkThumb_kMagic_OpenFileStore);
|
||||
|
||||
if ( outThumb )
|
||||
{
|
||||
morkBuilder* builder = ioStore->LazyGetBuilder(ev);
|
||||
if ( builder )
|
||||
{
|
||||
outThumb->mThumb_Total = (mork_count) fileEof;
|
||||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
morkBuilder::SlotStrongBuilder(builder, ev,
|
||||
&outThumb->mThumb_Builder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ioStore->NilStoreFileError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outThumb;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore)
|
||||
{
|
||||
morkThumb* outThumb = 0;
|
||||
if ( ioHeap && ioStore )
|
||||
{
|
||||
nsIMdbFile* file = ioStore->mStore_File;
|
||||
if ( file )
|
||||
{
|
||||
outThumb = new(*ioHeap, ev)
|
||||
morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap,
|
||||
morkThumb_kMagic_LargeCommit);
|
||||
|
||||
if ( outThumb )
|
||||
{
|
||||
morkWriter* writer = new(*ioHeap, ev)
|
||||
morkWriter(ev, morkUsage::kHeap, ioHeap, ioStore, file, ioHeap);
|
||||
if ( writer )
|
||||
{
|
||||
writer->mWriter_CommitGroupIdentity =
|
||||
++ioStore->mStore_CommitGroupIdentity;
|
||||
writer->mWriter_NeedDirtyAll = morkBool_kFalse;
|
||||
outThumb->mThumb_DoCollect = morkBool_kFalse;
|
||||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
|
||||
nsIMdbFile_SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
|
||||
outThumb->mThumb_Writer = writer; // pass writer ownership to thumb
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ioStore->NilStoreFileError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outThumb;
|
||||
}
|
||||
|
||||
/*static*/ morkThumb*
|
||||
morkThumb::Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect)
|
||||
{
|
||||
morkThumb* outThumb = 0;
|
||||
if ( ioHeap && ioStore )
|
||||
{
|
||||
nsIMdbFile* file = ioStore->mStore_File;
|
||||
if ( file )
|
||||
{
|
||||
outThumb = new(*ioHeap, ev)
|
||||
morkThumb(ev, morkUsage::kHeap, ioHeap, ioHeap,
|
||||
morkThumb_kMagic_CompressCommit);
|
||||
|
||||
if ( outThumb )
|
||||
{
|
||||
morkWriter* writer = new(*ioHeap, ev)
|
||||
morkWriter(ev, morkUsage::kHeap, ioHeap, ioStore, file, ioHeap);
|
||||
if ( writer )
|
||||
{
|
||||
writer->mWriter_NeedDirtyAll = morkBool_kTrue;
|
||||
outThumb->mThumb_DoCollect = inDoCollect;
|
||||
morkStore::SlotStrongStore(ioStore, ev, &outThumb->mThumb_Store);
|
||||
nsIMdbFile_SlotStrongFile(file, ev, &outThumb->mThumb_File);
|
||||
outThumb->mThumb_Writer = writer; // pass writer ownership to thumb
|
||||
|
||||
// cope with fact that parsed transaction groups are going away:
|
||||
ioStore->mStore_FirstCommitGroupPos = 0;
|
||||
ioStore->mStore_SecondCommitGroupPos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ioStore->NilStoreFileError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
|
||||
return outThumb;
|
||||
}
|
||||
|
||||
// { ===== begin non-poly methods imitating nsIMdbThumb =====
|
||||
void morkThumb::GetProgress(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
if ( outTotal )
|
||||
*outTotal = mThumb_Total;
|
||||
if ( outCurrent )
|
||||
*outCurrent = mThumb_Current;
|
||||
if ( outDone )
|
||||
*outDone = mThumb_Done;
|
||||
if ( outBroken )
|
||||
*outBroken = mThumb_Broken;
|
||||
}
|
||||
|
||||
void morkThumb::DoMore(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken)
|
||||
{
|
||||
if ( !mThumb_Done && !mThumb_Broken )
|
||||
{
|
||||
switch ( mThumb_Magic )
|
||||
{
|
||||
case morkThumb_kMagic_OpenFilePort: // 1 /* factory method */
|
||||
this->DoMore_OpenFilePort(ev); break;
|
||||
|
||||
case morkThumb_kMagic_OpenFileStore: // 2 /* factory method */
|
||||
this->DoMore_OpenFileStore(ev); break;
|
||||
|
||||
case morkThumb_kMagic_ExportToFormat: // 3 /* port method */
|
||||
this->DoMore_ExportToFormat(ev); break;
|
||||
|
||||
case morkThumb_kMagic_ImportContent: // 4 /* store method */
|
||||
this->DoMore_ImportContent(ev); break;
|
||||
|
||||
case morkThumb_kMagic_LargeCommit: // 5 /* store method */
|
||||
this->DoMore_LargeCommit(ev); break;
|
||||
|
||||
case morkThumb_kMagic_SessionCommit: // 6 /* store method */
|
||||
this->DoMore_SessionCommit(ev); break;
|
||||
|
||||
case morkThumb_kMagic_CompressCommit: // 7 /* store method */
|
||||
this->DoMore_CompressCommit(ev); break;
|
||||
|
||||
case morkThumb_kMagic_SearchManyColumns: // 8 /* table method */
|
||||
this->DoMore_SearchManyColumns(ev); break;
|
||||
|
||||
case morkThumb_kMagic_NewSortColumn: // 9 /* table metho) */
|
||||
this->DoMore_NewSortColumn(ev); break;
|
||||
|
||||
case morkThumb_kMagic_NewSortColumnWithCompare: // 10 /* table method */
|
||||
this->DoMore_NewSortColumnWithCompare(ev); break;
|
||||
|
||||
case morkThumb_kMagic_CloneSortColumn: // 11 /* table method */
|
||||
this->DoMore_CloneSortColumn(ev); break;
|
||||
|
||||
case morkThumb_kMagic_AddIndex: // 12 /* table method */
|
||||
this->DoMore_AddIndex(ev); break;
|
||||
|
||||
case morkThumb_kMagic_CutIndex: // 13 /* table method */
|
||||
this->DoMore_CutIndex(ev); break;
|
||||
|
||||
default:
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( outTotal )
|
||||
*outTotal = mThumb_Total;
|
||||
if ( outCurrent )
|
||||
*outCurrent = mThumb_Current;
|
||||
if ( outDone )
|
||||
*outDone = mThumb_Done;
|
||||
if ( outBroken )
|
||||
*outBroken = mThumb_Broken;
|
||||
}
|
||||
|
||||
void morkThumb::CancelAndBreakThumb(morkEnv* ev)
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
mThumb_Broken = morkBool_kTrue;
|
||||
}
|
||||
|
||||
// } ===== end non-poly methods imitating nsIMdbThumb =====
|
||||
|
||||
morkStore*
|
||||
morkThumb::ThumbToOpenStore(morkEnv* ev)
|
||||
// for orkinFactory::ThumbToOpenStore() after OpenFileStore()
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return mThumb_Store;
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_OpenFilePort(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_OpenFileStore(morkEnv* ev)
|
||||
{
|
||||
morkBuilder* builder = mThumb_Builder;
|
||||
if ( builder )
|
||||
{
|
||||
mork_pos pos = 0;
|
||||
builder->ParseMore(ev, &pos, &mThumb_Done, &mThumb_Broken);
|
||||
// mThumb_Total = builder->mBuilder_TotalCount;
|
||||
// mThumb_Current = builder->mBuilder_DoneCount;
|
||||
mThumb_Current = (mork_count) pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->NilThumbBuilderError(ev);
|
||||
mThumb_Broken = morkBool_kTrue;
|
||||
mThumb_Done = morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_ExportToFormat(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_ImportContent(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_LargeCommit(morkEnv* ev)
|
||||
{
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SessionCommit(morkEnv* ev)
|
||||
{
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_Commit(morkEnv* ev)
|
||||
{
|
||||
morkWriter* writer = mThumb_Writer;
|
||||
if ( writer )
|
||||
{
|
||||
writer->WriteMore(ev);
|
||||
mThumb_Total = writer->mWriter_TotalCount;
|
||||
mThumb_Current = writer->mWriter_DoneCount;
|
||||
mThumb_Done = ( ev->Bad() || writer->IsWritingDone() );
|
||||
mThumb_Broken = ev->Bad();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->NilThumbWriterError(ev);
|
||||
mThumb_Broken = morkBool_kTrue;
|
||||
mThumb_Done = morkBool_kTrue;
|
||||
}
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CompressCommit(morkEnv* ev)
|
||||
{
|
||||
this->DoMore_Commit(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_SearchManyColumns(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_NewSortColumn(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_NewSortColumnWithCompare(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CloneSortColumn(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_AddIndex(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
void morkThumb::DoMore_CutIndex(morkEnv* ev)
|
||||
{
|
||||
this->UnsupportedThumbMagicError(ev);
|
||||
}
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,212 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKTHUMB_
|
||||
#define _MORKTHUMB_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKOBJECT_
|
||||
#include "morkObject.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
#define morkThumb_kMagic_OpenFilePort 1 /* factory method */
|
||||
#define morkThumb_kMagic_OpenFileStore 2 /* factory method */
|
||||
#define morkThumb_kMagic_ExportToFormat 3 /* port method */
|
||||
#define morkThumb_kMagic_ImportContent 4 /* store method */
|
||||
#define morkThumb_kMagic_LargeCommit 5 /* store method */
|
||||
#define morkThumb_kMagic_SessionCommit 6 /* store method */
|
||||
#define morkThumb_kMagic_CompressCommit 7 /* store method */
|
||||
#define morkThumb_kMagic_SearchManyColumns 8 /* table method */
|
||||
#define morkThumb_kMagic_NewSortColumn 9 /* table metho) */
|
||||
#define morkThumb_kMagic_NewSortColumnWithCompare 10 /* table method */
|
||||
#define morkThumb_kMagic_CloneSortColumn 11 /* table method */
|
||||
#define morkThumb_kMagic_AddIndex 12 /* table method */
|
||||
#define morkThumb_kMagic_CutIndex 13 /* table method */
|
||||
|
||||
#define morkDerived_kThumb /*i*/ 0x5468 /* ascii 'Th' */
|
||||
|
||||
/*| morkThumb:
|
||||
|*/
|
||||
class morkThumb : public morkObject, public nsIMdbThumb {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// mork_color mBead_Color; // ID for this bead
|
||||
// morkHandle* mObject_Handle; // weak ref to handle for this object
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
// { ===== begin nsIMdbThumb methods =====
|
||||
NS_IMETHOD GetProgress(nsIMdbEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
||||
NS_IMETHOD DoMore(nsIMdbEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
||||
NS_IMETHOD CancelAndBreakThumb(nsIMdbEnv* ev);
|
||||
// } ===== end nsIMdbThumb methods =====
|
||||
|
||||
// might as well include all the return values here:
|
||||
|
||||
mork_magic mThumb_Magic; // magic sig different in each thumb type
|
||||
mork_count mThumb_Total;
|
||||
mork_count mThumb_Current;
|
||||
|
||||
mork_bool mThumb_Done;
|
||||
mork_bool mThumb_Broken;
|
||||
mork_u2 mThumb_Seed; // optional seed for u4 alignment padding
|
||||
|
||||
morkStore* mThumb_Store; // weak ref to created store
|
||||
nsIMdbFile* mThumb_File; // strong ref to file (store, import, export)
|
||||
morkWriter* mThumb_Writer; // strong ref to writer (for commit)
|
||||
morkBuilder* mThumb_Builder; // strong ref to builder (for store open)
|
||||
morkPort* mThumb_SourcePort; // strong ref to port for import
|
||||
|
||||
mork_bool mThumb_DoCollect; // influence whether a collect happens
|
||||
mork_bool mThumb_Pad[ 3 ]; // padding for u4 alignment
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseThumb() only if open
|
||||
virtual ~morkThumb(); // assert that CloseThumb() executed earlier
|
||||
|
||||
public: // morkThumb construction & destruction
|
||||
morkThumb(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, nsIMdbHeap* ioSlotHeap, mork_magic inMagic);
|
||||
void CloseThumb(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkThumb(const morkThumb& other);
|
||||
morkThumb& operator=(const morkThumb& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsThumb() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kThumb; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonThumbTypeError(morkEnv* ev);
|
||||
static void UnsupportedThumbMagicError(morkEnv* ev);
|
||||
|
||||
static void NilThumbStoreError(morkEnv* ev);
|
||||
static void NilThumbFileError(morkEnv* ev);
|
||||
static void NilThumbWriterError(morkEnv* ev);
|
||||
static void NilThumbBuilderError(morkEnv* ev);
|
||||
static void NilThumbSourcePortError(morkEnv* ev);
|
||||
|
||||
public: // 'do more' methods
|
||||
|
||||
void DoMore_OpenFilePort(morkEnv* ev);
|
||||
void DoMore_OpenFileStore(morkEnv* ev);
|
||||
void DoMore_ExportToFormat(morkEnv* ev);
|
||||
void DoMore_ImportContent(morkEnv* ev);
|
||||
void DoMore_LargeCommit(morkEnv* ev);
|
||||
void DoMore_SessionCommit(morkEnv* ev);
|
||||
void DoMore_CompressCommit(morkEnv* ev);
|
||||
void DoMore_Commit(morkEnv* ev);
|
||||
void DoMore_SearchManyColumns(morkEnv* ev);
|
||||
void DoMore_NewSortColumn(morkEnv* ev);
|
||||
void DoMore_NewSortColumnWithCompare(morkEnv* ev);
|
||||
void DoMore_CloneSortColumn(morkEnv* ev);
|
||||
void DoMore_AddIndex(morkEnv* ev);
|
||||
void DoMore_CutIndex(morkEnv* ev);
|
||||
|
||||
public: // other thumb methods
|
||||
|
||||
morkStore* ThumbToOpenStore(morkEnv* ev);
|
||||
// for orkinFactory::ThumbToOpenStore() after OpenFileStore()
|
||||
|
||||
public: // assorted thumb constructors
|
||||
|
||||
static morkThumb* Make_OpenFileStore(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore);
|
||||
|
||||
static morkThumb* Make_CompressCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, mork_bool inDoCollect);
|
||||
|
||||
static morkThumb* Make_LargeCommit(morkEnv* ev,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore);
|
||||
|
||||
// { ===== begin non-poly methods imitating nsIMdbThumb =====
|
||||
void GetProgress(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
||||
void DoMore(morkEnv* ev, mdb_count* outTotal,
|
||||
mdb_count* outCurrent, mdb_bool* outDone, mdb_bool* outBroken);
|
||||
|
||||
void CancelAndBreakThumb(morkEnv* ev);
|
||||
// } ===== end non-poly methods imitating nsIMdbThumb =====
|
||||
|
||||
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakThumb(morkThumb* me,
|
||||
morkEnv* ev, morkThumb** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongThumb(morkThumb* me,
|
||||
morkEnv* ev, morkThumb** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKTHUMB_ */
|
|
@ -0,0 +1,126 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKUNIQROWCURSOR_
|
||||
#define _MORKUNIQROWCURSOR_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKCURSOR_
|
||||
#include "morkCursor.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
class orkinTableRowCursor;
|
||||
// #define morkDerived_kUniqRowCursor /*i*/ 0x7352 /* ascii 'sR' */
|
||||
|
||||
class morkUniqRowCursor : public morkTableRowCursor { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
// morkFactory* mObject_Factory; // weak ref to suite factory
|
||||
|
||||
// mork_seed mCursor_Seed;
|
||||
// mork_pos mCursor_Pos;
|
||||
// mork_bool mCursor_DoFailOnSeedOutOfSync;
|
||||
// mork_u1 mCursor_Pad[ 3 ]; // explicitly pad to u4 alignment
|
||||
|
||||
// morkTable* mTableRowCursor_Table; // weak ref to table
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseUniqRowCursor()
|
||||
virtual ~morkUniqRowCursor(); // assert that close executed earlier
|
||||
|
||||
public: // morkUniqRowCursor construction & destruction
|
||||
morkUniqRowCursor(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkTable* ioTable, mork_pos inRowPos);
|
||||
void CloseUniqRowCursor(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkUniqRowCursor(const morkUniqRowCursor& other);
|
||||
morkUniqRowCursor& operator=(const morkUniqRowCursor& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
// mork_bool IsUniqRowCursor() const
|
||||
// { return IsNode() && mNode_Derived == morkDerived_kUniqRowCursor; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonUniqRowCursorTypeError(morkEnv* ev);
|
||||
|
||||
public: // other search row cursor methods
|
||||
|
||||
virtual mork_bool CanHaveDupRowMembers(morkEnv* ev);
|
||||
virtual mork_count GetMemberCount(morkEnv* ev);
|
||||
|
||||
virtual orkinTableRowCursor* AcquireUniqueRowCursorHandle(morkEnv* ev);
|
||||
|
||||
// virtual mdb_pos NextRowOid(morkEnv* ev, mdbOid* outOid);
|
||||
virtual morkRow* NextRow(morkEnv* ev, mdbOid* outOid, mdb_pos* outPos);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakUniqRowCursor(morkUniqRowCursor* me,
|
||||
morkEnv* ev, morkUniqRowCursor** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongUniqRowCursor(morkUniqRowCursor* me,
|
||||
morkEnv* ev, morkUniqRowCursor** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKUNIQROWCURSOR_ */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,375 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKWRITER_
|
||||
#define _MORKWRITER_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKMAP_
|
||||
#include "morkMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWMAP_
|
||||
#include "morkRowMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKTABLE_
|
||||
#include "morkTable.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMMAP_
|
||||
#include "morkAtomMap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKATOMSPACE_
|
||||
#include "morkAtomSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKROWSPACE_
|
||||
#include "morkRowSpace.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKSTREAM_
|
||||
#include "morkStream.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
#define morkWriter_kStreamBufSize /*i*/ (16 * 1024) /* buffer size for stream */
|
||||
|
||||
#define morkDerived_kWriter /*i*/ 0x5772 /* ascii 'Wr' */
|
||||
|
||||
#define morkWriter_kPhaseNothingDone 0 /* nothing has yet been done */
|
||||
#define morkWriter_kPhaseDirtyAllDone 1 /* DirtyAll() is done */
|
||||
#define morkWriter_kPhasePutHeaderDone 2 /* PutHeader() is done */
|
||||
|
||||
#define morkWriter_kPhaseRenumberAllDone 3 /* RenumberAll() is done */
|
||||
|
||||
#define morkWriter_kPhaseStoreAtomSpaces 4 /*mWriter_StoreAtomSpacesIter*/
|
||||
#define morkWriter_kPhaseAtomSpaceAtomAids 5 /*mWriter_AtomSpaceAtomAidsIter*/
|
||||
|
||||
#define morkWriter_kPhaseStoreRowSpacesTables 6 /*mWriter_StoreRowSpacesIter*/
|
||||
#define morkWriter_kPhaseRowSpaceTables 7 /*mWriter_RowSpaceTablesIter*/
|
||||
#define morkWriter_kPhaseTableRowArray 8 /*mWriter_TableRowArrayPos */
|
||||
|
||||
#define morkWriter_kPhaseStoreRowSpacesRows 9 /*mWriter_StoreRowSpacesIter*/
|
||||
#define morkWriter_kPhaseRowSpaceRows 10 /*mWriter_RowSpaceRowsIter*/
|
||||
|
||||
#define morkWriter_kPhaseContentDone 11 /* all content written */
|
||||
#define morkWriter_kPhaseWritingDone 12 /* everthing has been done */
|
||||
|
||||
#define morkWriter_kCountNumberOfPhases 13 /* part of mWrite_TotalCount */
|
||||
|
||||
#define morkWriter_kMaxColumnNameSize 128 /* longest writable col name */
|
||||
|
||||
#define morkWriter_kMaxIndent 66 /* default value for mWriter_MaxIndent */
|
||||
#define morkWriter_kMaxLine 78 /* default value for mWriter_MaxLine */
|
||||
|
||||
#define morkWriter_kYarnEscapeSlop 4 /* guess average yarn escape overhead */
|
||||
|
||||
#define morkWriter_kTableMetaCellDepth 4 /* */
|
||||
#define morkWriter_kTableMetaCellValueDepth 6 /* */
|
||||
|
||||
#define morkWriter_kDictMetaCellDepth 4 /* */
|
||||
#define morkWriter_kDictMetaCellValueDepth 6 /* */
|
||||
|
||||
#define morkWriter_kDictAliasDepth 2 /* */
|
||||
#define morkWriter_kDictAliasValueDepth 4 /* */
|
||||
|
||||
#define morkWriter_kRowDepth 2 /* */
|
||||
#define morkWriter_kRowCellDepth 4 /* */
|
||||
#define morkWriter_kRowCellValueDepth 6 /* */
|
||||
|
||||
#define morkWriter_kGroupBufSize 64 /* */
|
||||
|
||||
// v=1.1 retired on 23-Mar-99 (for metainfo one char column names)
|
||||
// v=1.2 retired on 20-Apr-99 (for ":c" suffix on table kind hex refs)
|
||||
// v=1.3 retired on 20-Apr-99 (for 1CE:m instead of ill-formed 1CE:^6D)
|
||||
#define morkWriter_kFileHeader "// <!-- <mdb:mork:z v=\"1.4\"/> -->"
|
||||
|
||||
class morkWriter : public morkNode { // row iterator
|
||||
|
||||
// public: // slots inherited from morkObject (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
morkStore* mWriter_Store; // weak ref to committing store
|
||||
nsIMdbFile* mWriter_File; // strong ref to store's file
|
||||
nsIMdbFile* mWriter_Bud; // strong ref to bud of mWriter_File
|
||||
morkStream* mWriter_Stream; // strong ref to stream on bud file
|
||||
nsIMdbHeap* mWriter_SlotHeap; // strong ref to slot heap
|
||||
|
||||
// GroupIdentity should be based on mStore_CommitGroupIdentity:
|
||||
mork_gid mWriter_CommitGroupIdentity; // transaction ID number
|
||||
|
||||
// GroupBuf holds a hex version of mWriter_CommitGroupIdentity:
|
||||
char mWriter_GroupBuf[ morkWriter_kGroupBufSize ];
|
||||
mork_fill mWriter_GroupBufFill; // actual bytes in GroupBuf
|
||||
|
||||
mork_count mWriter_TotalCount; // count of all things to be written
|
||||
mork_count mWriter_DoneCount; // count of things already written
|
||||
|
||||
mork_size mWriter_LineSize; // length of current line being written
|
||||
mork_size mWriter_MaxIndent; // line size forcing a line break
|
||||
mork_size mWriter_MaxLine; // line size forcing a value continuation
|
||||
|
||||
mork_cscode mWriter_TableForm; // current charset metainfo
|
||||
mork_scope mWriter_TableAtomScope; // current atom scope
|
||||
mork_scope mWriter_TableRowScope; // current row scope
|
||||
mork_kind mWriter_TableKind; // current table kind
|
||||
|
||||
mork_cscode mWriter_RowForm; // current charset metainfo
|
||||
mork_scope mWriter_RowAtomScope; // current atom scope
|
||||
mork_scope mWriter_RowScope; // current row scope
|
||||
|
||||
mork_cscode mWriter_DictForm; // current charset metainfo
|
||||
mork_scope mWriter_DictAtomScope; // current atom scope
|
||||
|
||||
mork_bool mWriter_NeedDirtyAll; // need to call DirtyAll()
|
||||
mork_bool mWriter_Incremental; // opposite of mWriter_NeedDirtyAll
|
||||
mork_bool mWriter_DidStartDict; // true when a dict has been started
|
||||
mork_bool mWriter_DidEndDict; // true when a dict has been ended
|
||||
|
||||
mork_bool mWriter_SuppressDirtyRowNewline; // for table meta rows
|
||||
mork_bool mWriter_DidStartGroup; // true when a group has been started
|
||||
mork_bool mWriter_DidEndGroup; // true when a group has been ended
|
||||
mork_u1 mWriter_Phase; // status of writing process
|
||||
|
||||
mork_bool mWriter_BeVerbose; // driven by env and table verbose settings:
|
||||
// mWriter_BeVerbose equals ( ev->mEnv_BeVerbose || table->IsTableVerbose() )
|
||||
|
||||
mork_u1 mWriter_Pad[ 3 ]; // for u4 alignment
|
||||
|
||||
mork_pos mWriter_TableRowArrayPos; // index into mTable_RowArray
|
||||
|
||||
char mWriter_SafeNameBuf[ (morkWriter_kMaxColumnNameSize * 2) + 4 ];
|
||||
// Note: extra four bytes in ColNameBuf means we can always append to yarn
|
||||
|
||||
char mWriter_ColNameBuf[ morkWriter_kMaxColumnNameSize + 4 ];
|
||||
// Note: extra four bytes in ColNameBuf means we can always append to yarn
|
||||
|
||||
mdbYarn mWriter_ColYarn; // a yarn to describe space in ColNameBuf:
|
||||
// mYarn_Buf == mWriter_ColNameBuf, mYarn_Size == morkWriter_kMaxColumnNameSize
|
||||
|
||||
mdbYarn mWriter_SafeYarn; // a yarn to describe space in ColNameBuf:
|
||||
// mYarn_Buf == mWriter_SafeNameBuf, mYarn_Size == (kMaxColumnNameSize * 2)
|
||||
|
||||
morkAtomSpaceMapIter mWriter_StoreAtomSpacesIter; // for mStore_AtomSpaces
|
||||
morkAtomAidMapIter mWriter_AtomSpaceAtomAidsIter; // for AtomSpace_AtomAids
|
||||
|
||||
morkRowSpaceMapIter mWriter_StoreRowSpacesIter; // for mStore_RowSpaces
|
||||
morkTableMapIter mWriter_RowSpaceTablesIter; // for mRowSpace_Tables
|
||||
|
||||
#ifdef MORK_ENABLE_PROBE_MAPS
|
||||
morkRowProbeMapIter mWriter_RowSpaceRowsIter; // for mRowSpace_Rows
|
||||
#else /*MORK_ENABLE_PROBE_MAPS*/
|
||||
morkRowMapIter mWriter_RowSpaceRowsIter; // for mRowSpace_Rows
|
||||
#endif /*MORK_ENABLE_PROBE_MAPS*/
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseWriter()
|
||||
virtual ~morkWriter(); // assert that close executed earlier
|
||||
|
||||
public: // morkWriter construction & destruction
|
||||
morkWriter(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioHeap, morkStore* ioStore, nsIMdbFile* ioFile,
|
||||
nsIMdbHeap* ioSlotHeap);
|
||||
void CloseWriter(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkWriter(const morkWriter& other);
|
||||
morkWriter& operator=(const morkWriter& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsWriter() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kWriter; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing & errors
|
||||
static void NonWriterTypeError(morkEnv* ev);
|
||||
static void NilWriterStoreError(morkEnv* ev);
|
||||
static void NilWriterBudError(morkEnv* ev);
|
||||
static void NilWriterStreamError(morkEnv* ev);
|
||||
static void NilWriterFileError(morkEnv* ev);
|
||||
static void UnsupportedPhaseError(morkEnv* ev);
|
||||
|
||||
public: // utitlities
|
||||
void ChangeRowForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictForm(morkEnv* ev, mork_cscode inNewForm);
|
||||
void ChangeDictAtomScope(morkEnv* ev, mork_scope inScope);
|
||||
|
||||
public: // inlines
|
||||
mork_bool DidStartDict() const { return mWriter_DidStartDict; }
|
||||
mork_bool DidEndDict() const { return mWriter_DidEndDict; }
|
||||
|
||||
void IndentAsNeeded(morkEnv* ev, mork_size inDepth)
|
||||
{
|
||||
if ( mWriter_LineSize > mWriter_MaxIndent )
|
||||
mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth);
|
||||
}
|
||||
|
||||
void IndentOverMaxLine(morkEnv* ev,
|
||||
mork_size inPendingSize, mork_size inDepth)
|
||||
{
|
||||
if ( mWriter_LineSize + inPendingSize > mWriter_MaxLine )
|
||||
mWriter_LineSize = mWriter_Stream->PutIndent(ev, inDepth);
|
||||
}
|
||||
|
||||
public: // delayed construction
|
||||
|
||||
void MakeWriterStream(morkEnv* ev); // give writer a suitable stream
|
||||
|
||||
public: // iterative/asynchronous writing
|
||||
|
||||
mork_bool WriteMore(morkEnv* ev); // call until IsWritingDone() is true
|
||||
|
||||
mork_bool IsWritingDone() const // don't call WriteMore() any longer?
|
||||
{ return mWriter_Phase == morkWriter_kPhaseWritingDone; }
|
||||
|
||||
public: // marking all content dirty
|
||||
mork_bool DirtyAll(morkEnv* ev);
|
||||
// DirtyAll() visits every store sub-object and marks
|
||||
// them dirty, including every table, row, cell, and atom. The return
|
||||
// equals ev->Good(), to show whether any error happened. This method is
|
||||
// intended for use in the beginning of a "compress commit" which writes
|
||||
// all store content, whether dirty or not. We dirty everything first so
|
||||
// that later iterations over content can mark things clean as they are
|
||||
// written, and organize the process of serialization so that objects are
|
||||
// written only at need (because of being dirty). Note the method can
|
||||
// stop early when any error happens, since this will abort any commit.
|
||||
|
||||
public: // group commit transactions
|
||||
|
||||
mork_bool StartGroup(morkEnv* ev);
|
||||
mork_bool CommitGroup(morkEnv* ev);
|
||||
mork_bool AbortGroup(morkEnv* ev);
|
||||
|
||||
public: // phase methods
|
||||
mork_bool OnNothingDone(morkEnv* ev);
|
||||
mork_bool OnDirtyAllDone(morkEnv* ev);
|
||||
mork_bool OnPutHeaderDone(morkEnv* ev);
|
||||
|
||||
mork_bool OnRenumberAllDone(morkEnv* ev);
|
||||
|
||||
mork_bool OnStoreAtomSpaces(morkEnv* ev);
|
||||
mork_bool OnAtomSpaceAtomAids(morkEnv* ev);
|
||||
|
||||
mork_bool OnStoreRowSpacesTables(morkEnv* ev);
|
||||
mork_bool OnRowSpaceTables(morkEnv* ev);
|
||||
mork_bool OnTableRowArray(morkEnv* ev);
|
||||
|
||||
mork_bool OnStoreRowSpacesRows(morkEnv* ev);
|
||||
mork_bool OnRowSpaceRows(morkEnv* ev);
|
||||
|
||||
mork_bool OnContentDone(morkEnv* ev);
|
||||
mork_bool OnWritingDone(morkEnv* ev);
|
||||
|
||||
public: // writing dict items first pass
|
||||
mork_bool PutTableDict(morkEnv* ev, morkTable* ioTable);
|
||||
mork_bool PutRowDict(morkEnv* ev, morkRow* ioRow);
|
||||
|
||||
public: // writing node content second pass
|
||||
mork_bool PutTable(morkEnv* ev, morkTable* ioTable);
|
||||
mork_bool PutRow(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
mork_bool PutVerboseRowCells(morkEnv* ev, morkRow* ioRow);
|
||||
|
||||
mork_bool PutCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
mork_bool PutVerboseCell(morkEnv* ev, morkCell* ioCell, mork_bool inWithVal);
|
||||
|
||||
mork_bool PutTableChange(morkEnv* ev, const morkTableChange* inChange);
|
||||
|
||||
public: // other writer methods
|
||||
|
||||
mork_bool IsYarnAllValue(const mdbYarn* inYarn);
|
||||
|
||||
mork_size WriteYarn(morkEnv* ev, const mdbYarn* inYarn);
|
||||
// return number of atom bytes written on the current line (which
|
||||
// implies that escaped line breaks will make the size value smaller
|
||||
// than the entire yarn's size, since only part goes on a last line).
|
||||
|
||||
mork_size WriteAtom(morkEnv* ev, const morkAtom* inAtom);
|
||||
// return number of atom bytes written on the current line (which
|
||||
// implies that escaped line breaks will make the size value smaller
|
||||
// than the entire atom's size, since only part goes on a last line).
|
||||
|
||||
void WriteAllStoreTables(morkEnv* ev);
|
||||
void WriteAtomSpaceAsDict(morkEnv* ev, morkAtomSpace* ioSpace);
|
||||
|
||||
void WriteTokenToTokenMetaCell(morkEnv* ev, mork_token inCol,
|
||||
mork_token inValue);
|
||||
void WriteStringToTokenDictCell(morkEnv* ev, const char* inCol,
|
||||
mork_token inValue);
|
||||
// Note inCol should begin with '(' and end with '=', with col in between.
|
||||
|
||||
void StartDict(morkEnv* ev);
|
||||
void EndDict(morkEnv* ev);
|
||||
|
||||
void StartTable(morkEnv* ev, morkTable* ioTable);
|
||||
void EndTable(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakWriter(morkWriter* me,
|
||||
morkEnv* ev, morkWriter** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongWriter(morkWriter* me,
|
||||
morkEnv* ev, morkWriter** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKTABLEROWCURSOR_ */
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKYARN_
|
||||
#include "morkYarn.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// ````` ````` ````` ````` `````
|
||||
// { ===== begin morkNode interface =====
|
||||
|
||||
/*public virtual*/ void
|
||||
morkYarn::CloseMorkNode(morkEnv* ev) /*i*/ // CloseYarn() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseYarn(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
/*public virtual*/
|
||||
morkYarn::~morkYarn() /*i*/ // assert CloseYarn() executed earlier
|
||||
{
|
||||
MORK_ASSERT(mYarn_Body.mYarn_Buf==0);
|
||||
}
|
||||
|
||||
/*public non-poly*/
|
||||
morkYarn::morkYarn(morkEnv* ev, /*i*/
|
||||
const morkUsage& inUsage, nsIMdbHeap* ioHeap)
|
||||
: morkNode(ev, inUsage, ioHeap)
|
||||
{
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kYarn;
|
||||
}
|
||||
|
||||
/*public non-poly*/ void
|
||||
morkYarn::CloseYarn(morkEnv* ev) /*i*/ // called by CloseMorkNode();
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
this->MarkShut();
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
// ````` ````` ````` ````` `````
|
||||
|
||||
/*static*/ void
|
||||
morkYarn::NonYarnTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkYarn");
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKYARN_
|
||||
#define _MORKYARN_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
#define morkDerived_kYarn /*i*/ 0x7952 /* ascii 'yR' */
|
||||
|
||||
/*| morkYarn: a reference counted nsIMdbYarn C struct. This is for use in those
|
||||
**| few cases where single instances of reference counted buffers are needed
|
||||
**| in Mork, and we expect few enough instances that overhead is not a factor
|
||||
**| in decided whether to use such a thing.
|
||||
|*/
|
||||
class morkYarn : public morkNode { // refcounted yarn
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
mdbYarn mYarn_Body;
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseYarn() only if open
|
||||
virtual ~morkYarn(); // assert that CloseYarn() executed earlier
|
||||
|
||||
public: // morkYarn construction & destruction
|
||||
morkYarn(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
|
||||
void CloseYarn(morkEnv* ev); // called by CloseMorkNode();
|
||||
|
||||
private: // copying is not allowed
|
||||
morkYarn(const morkYarn& other);
|
||||
morkYarn& operator=(const morkYarn& other);
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsYarn() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kYarn; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
public: // typing
|
||||
static void NonYarnTypeError(morkEnv* ev);
|
||||
|
||||
public: // typesafe refcounting inlines calling inherited morkNode methods
|
||||
static void SlotWeakYarn(morkYarn* me,
|
||||
morkEnv* ev, morkYarn** ioSlot)
|
||||
{ morkNode::SlotWeakNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
|
||||
static void SlotStrongYarn(morkYarn* me,
|
||||
morkEnv* ev, morkYarn** ioSlot)
|
||||
{ morkNode::SlotStrongNode((morkNode*) me, ev, (morkNode**) ioSlot); }
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKYARN_ */
|
|
@ -0,0 +1,577 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#include "morkZone.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
// public: // morkNode virtual methods
|
||||
void morkZone::CloseMorkNode(morkEnv* ev) // CloseZone() only if open
|
||||
{
|
||||
if ( this->IsOpenNode() )
|
||||
{
|
||||
this->MarkClosing();
|
||||
this->CloseZone(ev);
|
||||
this->MarkShut();
|
||||
}
|
||||
}
|
||||
|
||||
morkZone::~morkZone() // assert that CloseZone() executed earlier
|
||||
{
|
||||
MORK_ASSERT(this->IsShutNode());
|
||||
}
|
||||
|
||||
// public: // morkMap construction & destruction
|
||||
morkZone::morkZone(morkEnv* ev, const morkUsage& inUsage,
|
||||
nsIMdbHeap* ioNodeHeap, nsIMdbHeap* ioZoneHeap)
|
||||
: morkNode(ev, inUsage, ioNodeHeap)
|
||||
, mZone_Heap( 0 )
|
||||
, mZone_HeapVolume( 0 )
|
||||
, mZone_BlockVolume( 0 )
|
||||
, mZone_RunVolume( 0 )
|
||||
, mZone_ChipVolume( 0 )
|
||||
|
||||
, mZone_FreeOldRunVolume( 0 )
|
||||
|
||||
, mZone_HunkCount( 0 )
|
||||
, mZone_FreeOldRunCount( 0 )
|
||||
|
||||
, mZone_HunkList( 0 )
|
||||
, mZone_FreeOldRunList( 0 )
|
||||
|
||||
, mZone_At( 0 )
|
||||
, mZone_AtSize( 0 )
|
||||
|
||||
// morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
|
||||
{
|
||||
|
||||
morkRun** runs = mZone_FreeRuns;
|
||||
morkRun** end = runs + (morkZone_kBuckets + 1); // one past last slot
|
||||
--runs; // prepare for preincrement
|
||||
while ( ++runs < end ) // another slot in array?
|
||||
*runs = 0; // clear all the slots
|
||||
|
||||
if ( ev->Good() )
|
||||
{
|
||||
if ( ioZoneHeap )
|
||||
{
|
||||
nsIMdbHeap_SlotStrongHeap(ioZoneHeap, ev, &mZone_Heap);
|
||||
if ( ev->Good() )
|
||||
mNode_Derived = morkDerived_kZone;
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
}
|
||||
|
||||
void morkZone::CloseZone(morkEnv* ev) // called by CloseMorkNode()
|
||||
{
|
||||
if ( this )
|
||||
{
|
||||
if ( this->IsNode() )
|
||||
{
|
||||
nsIMdbHeap* heap = mZone_Heap;
|
||||
if ( heap )
|
||||
{
|
||||
morkHunk* hunk = 0;
|
||||
nsIMdbEnv* mev = ev->AsMdbEnv();
|
||||
|
||||
morkHunk* next = mZone_HunkList;
|
||||
while ( ( hunk = next ) != 0 )
|
||||
{
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
if ( !hunk->HunkGoodTag() )
|
||||
hunk->BadHunkTagWarning(ev);
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
next = hunk->HunkNext();
|
||||
heap->Free(mev, hunk);
|
||||
}
|
||||
}
|
||||
nsIMdbHeap_SlotStrongHeap((nsIMdbHeap*) 0, ev, &mZone_Heap);
|
||||
this->MarkShut();
|
||||
}
|
||||
else
|
||||
this->NonNodeError(ev);
|
||||
}
|
||||
else
|
||||
ev->NilPointerError();
|
||||
}
|
||||
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
/*static*/ void
|
||||
morkZone::NonZoneTypeError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("non morkZone");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkZone::NilZoneHeapError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("nil mZone_Heap");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkHunk::BadHunkTagWarning(morkEnv* ev)
|
||||
{
|
||||
ev->NewWarning("bad mHunk_Tag");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRun::BadRunTagError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad mRun_Tag");
|
||||
}
|
||||
|
||||
/*static*/ void
|
||||
morkRun::RunSizeAlignError(morkEnv* ev)
|
||||
{
|
||||
ev->NewError("bad RunSize() alignment");
|
||||
}
|
||||
|
||||
// { ===== begin morkZone methods =====
|
||||
|
||||
|
||||
mork_size morkZone::zone_grow_at(morkEnv* ev, mork_size inNeededSize)
|
||||
{
|
||||
mZone_At = 0; // remove any ref to current hunk
|
||||
mZone_AtSize = 0; // zero available bytes in current hunk
|
||||
|
||||
mork_size runSize = 0; // actual size of a particular run
|
||||
|
||||
// try to find a run in old run list with at least inNeededSize bytes:
|
||||
morkRun* run = mZone_FreeOldRunList; // cursor in list scan
|
||||
morkRun* prev = 0; // the node before run in the list scan
|
||||
|
||||
while ( run ) // another run in list to check?
|
||||
{
|
||||
morkOldRun* oldRun = (morkOldRun*) run;
|
||||
mork_size oldSize = oldRun->OldSize();
|
||||
if ( oldSize >= inNeededSize ) // found one big enough?
|
||||
{
|
||||
runSize = oldSize;
|
||||
break; // end while loop early
|
||||
}
|
||||
prev = run; // remember last position in singly linked list
|
||||
run = run->RunNext(); // advance cursor to next node in list
|
||||
}
|
||||
if ( runSize && run ) // found a usable old run?
|
||||
{
|
||||
morkRun* next = run->RunNext();
|
||||
if ( prev ) // another node in free list precedes run?
|
||||
prev->RunSetNext(next); // unlink run
|
||||
else
|
||||
mZone_FreeOldRunList = next; // unlink run from head of list
|
||||
|
||||
morkOldRun *oldRun = (morkOldRun *) run;
|
||||
oldRun->OldSetSize(runSize);
|
||||
mZone_At = (mork_u1*) run;
|
||||
mZone_AtSize = runSize;
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
mork_ip lowThree = ((mork_ip) mZone_At) & 7;
|
||||
if ( lowThree ) // not 8 byte aligned?
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
mork_ip lowTwo = ((mork_ip) mZone_At) & 3;
|
||||
if ( lowTwo ) // not 4 byte aligned?
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
ev->NewWarning("mZone_At not aligned");
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
}
|
||||
else // need to allocate a brand new run
|
||||
{
|
||||
inNeededSize += 7; // allow for possible alignment padding
|
||||
mork_size newSize = ( inNeededSize > morkZone_kNewHunkSize )?
|
||||
inNeededSize : morkZone_kNewHunkSize;
|
||||
|
||||
morkHunk* hunk = this->zone_new_hunk(ev, newSize);
|
||||
if ( hunk )
|
||||
{
|
||||
morkRun* hunkRun = hunk->HunkRun();
|
||||
mork_u1* at = (mork_u1*) hunkRun->RunAsBlock();
|
||||
mork_ip lowBits = ((mork_ip) at) & 7;
|
||||
if ( lowBits ) // not 8 byte aligned?
|
||||
{
|
||||
mork_ip skip = (8 - lowBits); // skip the complement to align
|
||||
at += skip;
|
||||
newSize -= skip;
|
||||
}
|
||||
mZone_At = at;
|
||||
mZone_AtSize = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
return mZone_AtSize;
|
||||
}
|
||||
|
||||
morkHunk* morkZone::zone_new_hunk(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
mdb_size hunkSize = inSize + sizeof(morkHunk);
|
||||
void* outBlock = 0; // we are going straight to the heap:
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), hunkSize, &outBlock);
|
||||
if ( outBlock )
|
||||
{
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_HeapVolume += hunkSize; // track all heap allocations
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
morkHunk* hunk = (morkHunk*) outBlock;
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
hunk->HunkInitTag();
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
hunk->HunkSetNext(mZone_HunkList);
|
||||
mZone_HunkList = hunk;
|
||||
++mZone_HunkCount;
|
||||
|
||||
morkRun* run = hunk->HunkRun();
|
||||
run->RunSetSize(inSize);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
run->RunInitTag();
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
return hunk;
|
||||
}
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
return (morkHunk*) 0;
|
||||
}
|
||||
|
||||
void* morkZone::zone_new_chip(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_BlockVolume += inSize; // sum sizes of both chips and runs
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
mork_u1* at = mZone_At;
|
||||
mork_size atSize = mZone_AtSize; // available bytes in current hunk
|
||||
if ( atSize >= inSize ) // current hunk can satisfy request?
|
||||
{
|
||||
mZone_At = at + inSize;
|
||||
mZone_AtSize = atSize - inSize;
|
||||
return at;
|
||||
}
|
||||
else if ( atSize > morkZone_kMaxHunkWaste ) // over max waste allowed?
|
||||
{
|
||||
morkHunk* hunk = this->zone_new_hunk(ev, inSize);
|
||||
if ( hunk )
|
||||
return hunk->HunkRun();
|
||||
|
||||
return (void*) 0; // show allocation has failed
|
||||
}
|
||||
else // get ourselves a new hunk for suballocation:
|
||||
{
|
||||
atSize = this->zone_grow_at(ev, inSize); // get a new hunk
|
||||
}
|
||||
|
||||
if ( atSize >= inSize ) // current hunk can satisfy request?
|
||||
{
|
||||
at = mZone_At;
|
||||
mZone_At = at + inSize;
|
||||
mZone_AtSize = atSize - inSize;
|
||||
return at;
|
||||
}
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // show allocation has failed
|
||||
}
|
||||
|
||||
void* morkZone::ZoneNewChip(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
inSize += 7;
|
||||
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
inSize += 3;
|
||||
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_ChipVolume += inSize; // sum sizes of chips only
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
return this->zone_new_chip(ev, inSize);
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
|
||||
}
|
||||
|
||||
// public: // ...but runs do indeed know how big they are
|
||||
void* morkZone::ZoneNewRun(morkEnv* ev, mdb_size inSize) // alloc
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
inSize += morkZone_kRoundAdd;
|
||||
inSize &= morkZone_kRoundMask;
|
||||
if ( inSize <= morkZone_kMaxCachedRun )
|
||||
{
|
||||
morkRun** bucket = mZone_FreeRuns + (inSize >> morkZone_kRoundBits);
|
||||
morkRun* hit = *bucket;
|
||||
if ( hit ) // cache hit?
|
||||
{
|
||||
*bucket = hit->RunNext();
|
||||
hit->RunSetSize(inSize);
|
||||
return hit->RunAsBlock();
|
||||
}
|
||||
}
|
||||
mdb_size blockSize = inSize + sizeof(morkRun); // plus run overhead
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_RunVolume += blockSize; // sum sizes of runs only
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
morkRun* run = (morkRun*) this->zone_new_chip(ev, blockSize);
|
||||
if ( run )
|
||||
{
|
||||
run->RunSetSize(inSize);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
run->RunInitTag();
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
return run->RunAsBlock();
|
||||
}
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // indicate failed allocation
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Alloc(ev->AsMdbEnv(), inSize, &outBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
void morkZone::ZoneZapRun(morkEnv* ev, void* ioRunBlock) // free
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
|
||||
mdb_size runSize = run->RunSize();
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_BlockVolume -= runSize; // tracking sizes of both chips and runs
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
else if ( !ioRunBlock )
|
||||
ev->NilPointerError();
|
||||
else if ( runSize & morkZone_kRoundAdd )
|
||||
run->RunSizeAlignError(ev);
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
else if ( !run->RunGoodTag() )
|
||||
run->BadRunTagError(ev);
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
if ( runSize <= morkZone_kMaxCachedRun ) // goes into free run list?
|
||||
{
|
||||
morkRun** bucket = mZone_FreeRuns + (runSize >> morkZone_kRoundBits);
|
||||
run->RunSetNext(*bucket); // push onto free run list
|
||||
*bucket = run;
|
||||
}
|
||||
else // free old run list
|
||||
{
|
||||
run->RunSetNext(mZone_FreeOldRunList); // push onto free old run list
|
||||
mZone_FreeOldRunList = run;
|
||||
++mZone_FreeOldRunCount;
|
||||
#ifdef morkZone_CONFIG_VOL_STATS
|
||||
mZone_FreeOldRunVolume += runSize;
|
||||
#endif /* morkZone_CONFIG_VOL_STATS */
|
||||
|
||||
morkOldRun* oldRun = (morkOldRun*) run; // to access extra size slot
|
||||
oldRun->OldSetSize(runSize); // so we know how big this is later
|
||||
}
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
void* morkZone::ZoneGrowRun(morkEnv* ev, void* ioRunBlock, mdb_size inSize)
|
||||
{
|
||||
#ifdef morkZone_CONFIG_ARENA
|
||||
|
||||
morkRun* run = morkRun::BlockAsRun(ioRunBlock);
|
||||
mdb_size runSize = run->RunSize();
|
||||
|
||||
#ifdef morkZone_CONFIG_DEBUG
|
||||
if ( !this->IsZone() )
|
||||
this->NonZoneTypeError(ev);
|
||||
else if ( !mZone_Heap )
|
||||
this->NilZoneHeapError(ev);
|
||||
#endif /*morkZone_CONFIG_DEBUG*/
|
||||
|
||||
#ifdef morkZone_CONFIG_ALIGN_8
|
||||
inSize += 7;
|
||||
inSize &= ~((mork_ip) 7); // force to multiple of 8 bytes
|
||||
#else /*morkZone_CONFIG_ALIGN_8*/
|
||||
inSize += 3;
|
||||
inSize &= ~((mork_ip) 3); // force to multiple of 4 bytes
|
||||
#endif /*morkZone_CONFIG_ALIGN_8*/
|
||||
|
||||
if ( inSize > runSize )
|
||||
{
|
||||
void* newBuf = this->ZoneNewRun(ev, inSize);
|
||||
if ( newBuf )
|
||||
{
|
||||
MORK_MEMCPY(newBuf, ioRunBlock, runSize);
|
||||
this->ZoneZapRun(ev, ioRunBlock);
|
||||
|
||||
return newBuf;
|
||||
}
|
||||
}
|
||||
else
|
||||
return ioRunBlock; // old size is big enough
|
||||
|
||||
if ( ev->Good() ) // got this far without any error reported yet?
|
||||
ev->OutOfMemoryError();
|
||||
|
||||
return (void*) 0; // indicate failed allocation
|
||||
|
||||
#else /*morkZone_CONFIG_ARENA*/
|
||||
void* outBlock = 0;
|
||||
mZone_Heap->Free(ev->AsMdbEnv(), ioRunBlock);
|
||||
return outBlock;
|
||||
#endif /*morkZone_CONFIG_ARENA*/
|
||||
}
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::Alloc(nsIMdbEnv* mev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock) // memory block of inSize bytes, or nil
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
void* block = 0;
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
block = this->ZoneNewRun(ev, inSize);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
else
|
||||
outErr = 1;
|
||||
|
||||
if ( outBlock )
|
||||
*outBlock = block;
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::Free(nsIMdbEnv* mev, // free block allocated earlier by Alloc()
|
||||
void* inBlock)
|
||||
{
|
||||
mdb_err outErr = 0;
|
||||
if ( inBlock )
|
||||
{
|
||||
morkEnv* ev = morkEnv::FromMdbEnv(mev);
|
||||
if ( ev )
|
||||
{
|
||||
this->ZoneZapRun(ev, inBlock);
|
||||
outErr = ev->AsErr();
|
||||
}
|
||||
else
|
||||
outErr = 1;
|
||||
}
|
||||
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::HeapAddStrongRef(nsIMdbEnv* mev) // does nothing
|
||||
{
|
||||
MORK_USED_1(mev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
morkZone::HeapCutStrongRef(nsIMdbEnv* mev) // does nothing
|
||||
{
|
||||
MORK_USED_1(mev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MORKZONE_
|
||||
#define _MORKZONE_ 1
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKNODE_
|
||||
#include "morkNode.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKDEQUE_
|
||||
#include "morkDeque.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| CONFIG_DEBUG: do paranoid debug checks if defined.
|
||||
|*/
|
||||
#ifdef MORK_DEBUG
|
||||
#define morkZone_CONFIG_DEBUG 1 /* debug paranoid if defined */
|
||||
#endif /*MORK_DEBUG*/
|
||||
|
||||
/*| CONFIG_STATS: keep volume and usage statistics.
|
||||
|*/
|
||||
#define morkZone_CONFIG_VOL_STATS 1 /* count space used by zone instance */
|
||||
|
||||
/*| CONFIG_ARENA: if this is defined, then the morkZone class will alloc big
|
||||
**| blocks from the zone's heap, and suballocate from these. If undefined,
|
||||
**| then morkZone will just pass all calls through to the zone's heap.
|
||||
|*/
|
||||
#ifdef MORK_ENABLE_ZONE_ARENAS
|
||||
#define morkZone_CONFIG_ARENA 1 /* be arena, if defined; otherwise no-op */
|
||||
#endif /*MORK_ENABLE_ZONE_ARENAS*/
|
||||
|
||||
/*| CONFIG_ALIGN_8: if this is defined, then the morkZone class will give
|
||||
**| blocks 8 byte alignment instead of only 4 byte alignment.
|
||||
|*/
|
||||
#ifdef MORK_CONFIG_ALIGN_8
|
||||
#define morkZone_CONFIG_ALIGN_8 1 /* ifdef: align to 8 bytes, otherwise 4 */
|
||||
#endif /*MORK_CONFIG_ALIGN_8*/
|
||||
|
||||
/*| CONFIG_PTR_SIZE_4: if this is defined, then the morkZone class will
|
||||
**| assume sizeof(void*) == 4, so a tag slot for padding is needed.
|
||||
|*/
|
||||
#ifdef MORK_CONFIG_PTR_SIZE_4
|
||||
#define morkZone_CONFIG_PTR_SIZE_4 1 /* ifdef: sizeof(void*) == 4 */
|
||||
#endif /*MORK_CONFIG_PTR_SIZE_4*/
|
||||
|
||||
/*| morkZone_USE_TAG_SLOT: if this is defined, then define slot mRun_Tag
|
||||
**| in order to achieve eight byte alignment after the mRun_Next slot.
|
||||
|*/
|
||||
#if defined(morkZone_CONFIG_ALIGN_8) && defined(morkZone_CONFIG_PTR_SIZE_4)
|
||||
#define morkRun_USE_TAG_SLOT 1 /* need mRun_Tag slot inside morkRun */
|
||||
#define morkHunk_USE_TAG_SLOT 1 /* need mHunk_Tag slot inside morkHunk */
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkRun_kTag ((mork_u4) 0x6D52754E ) /* ascii 'mRuN' */
|
||||
|
||||
/*| morkRun: structure used by morkZone for sized blocks
|
||||
|*/
|
||||
class morkRun {
|
||||
|
||||
protected: // member variable slots
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
mork_u4 mRun_Tag; // force 8 byte alignment after mRun_Next
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
morkRun* mRun_Next;
|
||||
|
||||
public: // pointer interpretation of mRun_Next (when inside a list):
|
||||
morkRun* RunNext() const { return mRun_Next; }
|
||||
void RunSetNext(morkRun* ioNext) { mRun_Next = ioNext; }
|
||||
|
||||
public: // size interpretation of mRun_Next (when not inside a list):
|
||||
mork_size RunSize() const { return (mork_size) ((mork_ip) mRun_Next); }
|
||||
void RunSetSize(mork_size inSize)
|
||||
{ mRun_Next = (morkRun*) ((mork_ip) inSize); }
|
||||
|
||||
public: // maintenance and testing of optional tag magic signature slot:
|
||||
#ifdef morkRun_USE_TAG_SLOT
|
||||
void RunInitTag() { mRun_Tag = morkRun_kTag; }
|
||||
mork_bool RunGoodTag() { return ( mRun_Tag == morkRun_kTag ); }
|
||||
#endif /* morkRun_USE_TAG_SLOT */
|
||||
|
||||
public: // conversion back and forth to inline block following run instance:
|
||||
void* RunAsBlock() { return (((mork_u1*) this) + sizeof(morkRun)); }
|
||||
|
||||
static morkRun* BlockAsRun(void* ioBlock)
|
||||
{ return (morkRun*) (((mork_u1*) ioBlock) - sizeof(morkRun)); }
|
||||
|
||||
public: // typing & errors
|
||||
static void BadRunTagError(morkEnv* ev);
|
||||
static void RunSizeAlignError(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
/*| morkOldRun: more space to record size when run is put into old free list
|
||||
|*/
|
||||
class morkOldRun : public morkRun {
|
||||
|
||||
protected: // need another size field when mRun_Next is used for linkage:
|
||||
mdb_size mOldRun_Size;
|
||||
|
||||
public: // size getter/setter
|
||||
mork_size OldSize() const { return mOldRun_Size; }
|
||||
void OldSetSize(mork_size inSize) { mOldRun_Size = inSize; }
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define morkHunk_kTag ((mork_u4) 0x68556E4B ) /* ascii 'hUnK' */
|
||||
|
||||
/*| morkHunk: structure used by morkZone for heap allocations.
|
||||
|*/
|
||||
class morkHunk {
|
||||
|
||||
protected: // member variable slots
|
||||
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
mork_u4 mHunk_Tag; // force 8 byte alignment after mHunk_Next
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
morkHunk* mHunk_Next;
|
||||
|
||||
morkRun mHunk_Run;
|
||||
|
||||
public: // setters
|
||||
void HunkSetNext(morkHunk* ioNext) { mHunk_Next = ioNext; }
|
||||
|
||||
public: // getters
|
||||
morkHunk* HunkNext() const { return mHunk_Next; }
|
||||
|
||||
morkRun* HunkRun() { return &mHunk_Run; }
|
||||
|
||||
public: // maintenance and testing of optional tag magic signature slot:
|
||||
#ifdef morkHunk_USE_TAG_SLOT
|
||||
void HunkInitTag() { mHunk_Tag = morkHunk_kTag; }
|
||||
mork_bool HunkGoodTag() { return ( mHunk_Tag == morkHunk_kTag ); }
|
||||
#endif /* morkHunk_USE_TAG_SLOT */
|
||||
|
||||
public: // typing & errors
|
||||
static void BadHunkTagWarning(morkEnv* ev);
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
/*| kNewHunkSize: the default size for a hunk, assuming we must allocate
|
||||
**| a new one whenever the free hunk list does not already have. Note this
|
||||
**| number should not be changed without also considering suitable changes
|
||||
**| in the related kMaxHunkWaste and kMinHunkSize constants.
|
||||
|*/
|
||||
#define morkZone_kNewHunkSize ((mork_size) (64 * 1024)) /* 64K per hunk */
|
||||
|
||||
/*| kMaxFreeVolume: some number of bytes of free space in the free hunk list
|
||||
**| over which we no longer want to add more free hunks to the list, for fear
|
||||
**| of accumulating too much unused, fragmented free space. This should be a
|
||||
**| small multiple of kNewHunkSize, say about two to four times as great, to
|
||||
**| allow for no more free hunk space than fits in a handful of new hunks.
|
||||
**| This strategy will let us usefuly accumulate "some" free space in the
|
||||
**| free hunk list, but without accumulating "too much" free space that way.
|
||||
|*/
|
||||
#define morkZone_kMaxFreeVolume (morkZone_kNewHunkSize * 3)
|
||||
|
||||
/*| kMaxHunkWaste: if a current request is larger than this, and we cannot
|
||||
**| satisfy the request with the current hunk, then we just allocate the
|
||||
**| block from the heap without changing the current hunk. Basically this
|
||||
**| number represents the largest amount of memory we are willing to waste,
|
||||
**| since a block request barely less than this can cause the current hunk
|
||||
**| to be retired (with any unused space wasted) as well get a new hunk.
|
||||
|*/
|
||||
#define morkZone_kMaxHunkWaste ((mork_size) 4096) /* 1/16 kNewHunkSize */
|
||||
|
||||
/*| kRound*: the algorithm for rounding up allocation sizes for caching
|
||||
**| in free lists works like the following. We add kRoundAdd to any size
|
||||
**| requested, and then bitwise AND with kRoundMask, and this will give us
|
||||
**| the smallest multiple of kRoundSize that is at least as large as the
|
||||
**| requested size. Then if we rightshift this number by kRoundBits, we
|
||||
**| will have the index into the mZone_FreeRuns array which will hold any
|
||||
**| cache runs of that size. So 4 bits of shift gives us a granularity
|
||||
**| of 16 bytes, so that free lists will hold successive runs that are
|
||||
**| 16 bytes greater than the next smaller run size. If we have 256 free
|
||||
**| lists of nonzero sized runs altogether, then the largest run that can
|
||||
**| be cached is 4096, or 4K (since 4096 == 16 * 256). A larger run that
|
||||
**| gets freed will go in to the free hunk list (or back to the heap).
|
||||
|*/
|
||||
#define morkZone_kRoundBits 4 /* bits to round-up size for free lists */
|
||||
#define morkZone_kRoundSize (1 << morkZone_kRoundBits)
|
||||
#define morkZone_kRoundAdd ((1 << morkZone_kRoundBits) - 1)
|
||||
#define morkZone_kRoundMask (~ ((mork_ip) morkZone_kRoundAdd))
|
||||
|
||||
#define morkZone_kBuckets 256 /* number of distinct free lists */
|
||||
|
||||
/*| kMaxCachedRun: the largest run that will be stored inside a free
|
||||
**| list of old zapped runs. A run larger than this cannot be put in
|
||||
**| a free list, and must be allocated from the heap at need, and put
|
||||
**| into the free hunk list when discarded.
|
||||
|*/
|
||||
#define morkZone_kMaxCachedRun (morkZone_kBuckets * morkZone_kRoundSize)
|
||||
|
||||
#define morkDerived_kZone /*i*/ 0x5A6E /* ascii 'Zn' */
|
||||
|
||||
/*| morkZone: a pooled memory allocator like an NSPR arena. The term 'zone'
|
||||
**| is roughly synonymous with 'heap'. I avoid calling this class a "heap"
|
||||
**| to avoid any confusion with nsIMdbHeap, and I avoid calling this class
|
||||
**| an arean to avoid confusion with NSPR usage.
|
||||
|*/
|
||||
class morkZone : public morkNode, public nsIMdbHeap {
|
||||
|
||||
// public: // slots inherited from morkNode (meant to inform only)
|
||||
// nsIMdbHeap* mNode_Heap;
|
||||
|
||||
// mork_base mNode_Base; // must equal morkBase_kNode
|
||||
// mork_derived mNode_Derived; // depends on specific node subclass
|
||||
|
||||
// mork_access mNode_Access; // kOpen, kClosing, kShut, or kDead
|
||||
// mork_usage mNode_Usage; // kHeap, kStack, kMember, kGlobal, kNone
|
||||
// mork_able mNode_Mutable; // can this node be modified?
|
||||
// mork_load mNode_Load; // is this node clean or dirty?
|
||||
|
||||
// mork_uses mNode_Uses; // refcount for strong refs
|
||||
// mork_refs mNode_Refs; // refcount for strong refs + weak refs
|
||||
|
||||
public: // state is public because the entire Mork system is private
|
||||
|
||||
nsIMdbHeap* mZone_Heap; // strong ref to heap allocating all space
|
||||
|
||||
mork_size mZone_HeapVolume; // total bytes allocated from heap
|
||||
mork_size mZone_BlockVolume; // total bytes in all zone blocks
|
||||
mork_size mZone_RunVolume; // total bytes in all zone runs
|
||||
mork_size mZone_ChipVolume; // total bytes in all zone chips
|
||||
|
||||
mork_size mZone_FreeOldRunVolume; // total bytes in all used hunks
|
||||
|
||||
mork_count mZone_HunkCount; // total number of used hunks
|
||||
mork_count mZone_FreeOldRunCount; // total free old runs
|
||||
|
||||
morkHunk* mZone_HunkList; // linked list of all used hunks
|
||||
morkRun* mZone_FreeOldRunList; // linked list of free old runs
|
||||
|
||||
// note mZone_At is a byte pointer for single byte address arithmetic:
|
||||
mork_u1* mZone_At; // current position in most recent hunk
|
||||
mork_size mZone_AtSize; // number of bytes remaining in this hunk
|
||||
|
||||
// kBuckets+1 so indexes zero through kBuckets are all okay to use:
|
||||
|
||||
morkRun* mZone_FreeRuns[ morkZone_kBuckets + 1 ];
|
||||
// Each piece of memory stored in list mZone_FreeRuns[ i ] has an
|
||||
// allocation size equal to sizeof(morkRun) + (i * kRoundSize), so
|
||||
// that callers can be given a piece of memory with (i * kRoundSize)
|
||||
// bytes of writeable space while reserving the first sizeof(morkRun)
|
||||
// bytes to keep track of size information for later re-use. Note
|
||||
// that mZone_FreeRuns[ 0 ] is unused because no run will be zero
|
||||
// bytes in size (and morkZone plans to complain about zero sizes).
|
||||
|
||||
protected: // zone utilities
|
||||
|
||||
mork_size zone_grow_at(morkEnv* ev, mork_size inNeededSize);
|
||||
|
||||
void* zone_new_chip(morkEnv* ev, mdb_size inSize); // alloc
|
||||
morkHunk* zone_new_hunk(morkEnv* ev, mdb_size inRunSize); // alloc
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
public:
|
||||
NS_IMETHOD Alloc(nsIMdbEnv* ev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock); // memory block of inSize bytes, or nil
|
||||
|
||||
NS_IMETHOD Free(nsIMdbEnv* ev, // free block allocated earlier by Alloc()
|
||||
void* inBlock);
|
||||
|
||||
NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
||||
// { ===== begin morkNode interface =====
|
||||
public: // morkNode virtual methods
|
||||
virtual void CloseMorkNode(morkEnv* ev); // CloseZone() only if open
|
||||
virtual ~morkZone(); // assert that CloseMap() executed earlier
|
||||
|
||||
public: // morkMap construction & destruction
|
||||
morkZone(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioNodeHeap,
|
||||
nsIMdbHeap* ioZoneHeap);
|
||||
|
||||
void CloseZone(morkEnv* ev); // called by CloseMorkNode()
|
||||
|
||||
public: // dynamic type identification
|
||||
mork_bool IsZone() const
|
||||
{ return IsNode() && mNode_Derived == morkDerived_kZone; }
|
||||
// } ===== end morkNode methods =====
|
||||
|
||||
// { ===== begin morkZone methods =====
|
||||
public: // chips do not know how big they are...
|
||||
void* ZoneNewChip(morkEnv* ev, mdb_size inSize); // alloc
|
||||
|
||||
public: // ...but runs do indeed know how big they are
|
||||
void* ZoneNewRun(morkEnv* ev, mdb_size inSize); // alloc
|
||||
void ZoneZapRun(morkEnv* ev, void* ioRunBody); // free
|
||||
void* ZoneGrowRun(morkEnv* ev, void* ioRunBody, mdb_size inSize); // realloc
|
||||
|
||||
// } ===== end morkZone methods =====
|
||||
|
||||
public: // typing & errors
|
||||
static void NonZoneTypeError(morkEnv* ev);
|
||||
static void NilZoneHeapError(morkEnv* ev);
|
||||
static void BadZoneTagError(morkEnv* ev);
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _MORKZONE_ */
|
|
@ -0,0 +1,189 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ORKINHEAP_
|
||||
#include "orkinHeap.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORKENV_
|
||||
#include "morkEnv.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
|
||||
orkinHeap::orkinHeap() // does nothing
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
: sHeap_AllocCount( 0 )
|
||||
, sHeap_FreeCount( 0 )
|
||||
, sHeap_BlockCount( 0 )
|
||||
|
||||
, sHeap_BlockVolume( 0 )
|
||||
, sHeap_HighWaterVolume( 0 )
|
||||
, sHeap_HighWaterTenKilo( 0 )
|
||||
, sHeap_HighWaterHundredKilo( 0 )
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/
|
||||
orkinHeap::~orkinHeap() // does nothing
|
||||
{
|
||||
}
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
/*virtual*/ mdb_err
|
||||
orkinHeap::Alloc(nsIMdbEnv* mev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock) // memory block of inSize bytes, or nil
|
||||
{
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
mdb_size realSize = inSize;
|
||||
inSize += 12; // sizeof(mork_u4) * 3
|
||||
++sHeap_AllocCount;
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
|
||||
MORK_USED_1(mev);
|
||||
mdb_err outErr = 0;
|
||||
void* block = malloc(inSize);
|
||||
if ( !block )
|
||||
outErr = morkEnv_kOutOfMemoryError;
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
else
|
||||
{
|
||||
printf("%lx allocating %d\n", this, realSize);
|
||||
mork_u4* array = (mork_u4*) block;
|
||||
*array++ = (mork_u4) this;
|
||||
*array++ = realSize;
|
||||
*array++ = orkinHeap_kTag;
|
||||
block = array;
|
||||
++sHeap_BlockCount;
|
||||
mork_num blockVol = sHeap_BlockVolume + realSize;
|
||||
sHeap_BlockVolume = blockVol;
|
||||
if ( blockVol > sHeap_HighWaterVolume )
|
||||
{
|
||||
sHeap_HighWaterVolume = blockVol;
|
||||
|
||||
mork_num tenKiloVol = blockVol / (10 * 1024);
|
||||
if ( tenKiloVol > sHeap_HighWaterTenKilo )
|
||||
{
|
||||
sHeap_HighWaterTenKilo = tenKiloVol;
|
||||
|
||||
mork_num hundredKiloVol = blockVol / (100 * 1024);
|
||||
if ( hundredKiloVol > sHeap_HighWaterHundredKilo )
|
||||
sHeap_HighWaterHundredKilo = hundredKiloVol;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
|
||||
MORK_ASSERT(outBlock);
|
||||
if ( outBlock )
|
||||
*outBlock = block;
|
||||
return outErr;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinHeap::Free(nsIMdbEnv* mev, // free block allocated earlier by Alloc()
|
||||
void* inBlock)
|
||||
{
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
++sHeap_FreeCount;
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
|
||||
MORK_USED_1(mev);
|
||||
MORK_ASSERT(inBlock);
|
||||
if ( inBlock )
|
||||
{
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
morkEnv* ev = 0; //morkEnv::FromMdbEnv(mev);
|
||||
mork_u4* array = (mork_u4*) inBlock;
|
||||
if ( *--array != orkinHeap_kTag )
|
||||
{
|
||||
if ( ev )
|
||||
ev->NewWarning("heap block tag not hEaP");
|
||||
}
|
||||
mork_u4 realSize = *--array;
|
||||
inBlock = --array; // skip over heap ptr too.
|
||||
|
||||
printf("%lx freeing %d\n", this, realSize);
|
||||
if ( sHeap_BlockCount )
|
||||
--sHeap_BlockCount;
|
||||
else if ( ev )
|
||||
ev->NewWarning("sHeap_BlockCount underflow");
|
||||
|
||||
if ( sHeap_BlockVolume >= realSize )
|
||||
sHeap_BlockVolume -= realSize;
|
||||
else if ( ev )
|
||||
{
|
||||
sHeap_BlockVolume = 0;
|
||||
ev->NewWarning("sHeap_BlockVolume underflow");
|
||||
}
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
|
||||
free(inBlock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinHeap::HeapAddStrongRef(nsIMdbEnv* ev) // does nothing
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*virtual*/ mdb_err
|
||||
orkinHeap::HeapCutStrongRef(nsIMdbEnv* ev) // does nothing
|
||||
{
|
||||
MORK_USED_1(ev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
|
@ -0,0 +1,103 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1999
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef _ORKINHEAP_
|
||||
#define _ORKINHEAP_ 1
|
||||
|
||||
#ifndef _MDB_
|
||||
#include "mdb.h"
|
||||
#endif
|
||||
|
||||
#ifndef _MORK_
|
||||
#include "mork.h"
|
||||
#endif
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#define orkinHeap_kTag 0x68456150 /* ascii 'hEaP' */
|
||||
|
||||
/*| orkinHeap:
|
||||
|*/
|
||||
class orkinHeap : public nsIMdbHeap { //
|
||||
|
||||
#ifdef MORK_DEBUG_HEAP_STATS
|
||||
protected:
|
||||
mork_num sHeap_AllocCount; // number of times Alloc() is called
|
||||
mork_num sHeap_FreeCount; // number of times Free() is called
|
||||
mork_num sHeap_BlockCount; // number of outstanding blocks
|
||||
|
||||
mork_num sHeap_BlockVolume; // sum of sizes for all outstanding blocks
|
||||
mork_num sHeap_HighWaterVolume; // largest value of sHeap_BlockVolume seen
|
||||
mork_num sHeap_HighWaterTenKilo; // HighWaterVolume in 10K granularity
|
||||
mork_num sHeap_HighWaterHundredKilo; // HighWaterVolume in 100K granularity
|
||||
|
||||
public: // getters
|
||||
mork_num HeapAllocCount() const { return sHeap_AllocCount; }
|
||||
mork_num HeapFreeCount() const { return sHeap_FreeCount; }
|
||||
mork_num HeapBlockCount() const { return sHeap_AllocCount - sHeap_FreeCount; }
|
||||
|
||||
mork_num HeapBlockVolume() const { return sHeap_BlockVolume; }
|
||||
mork_num HeapHighWaterVolume() const { return sHeap_HighWaterVolume; }
|
||||
#endif /*MORK_DEBUG_HEAP_STATS*/
|
||||
|
||||
public:
|
||||
orkinHeap(); // does nothing
|
||||
virtual ~orkinHeap(); // does nothing
|
||||
|
||||
private: // copying is not allowed
|
||||
orkinHeap(const orkinHeap& other);
|
||||
orkinHeap& operator=(const orkinHeap& other);
|
||||
|
||||
public:
|
||||
|
||||
// { ===== begin nsIMdbHeap methods =====
|
||||
NS_IMETHOD Alloc(nsIMdbEnv* ev, // allocate a piece of memory
|
||||
mdb_size inSize, // requested size of new memory block
|
||||
void** outBlock); // memory block of inSize bytes, or nil
|
||||
|
||||
NS_IMETHOD Free(nsIMdbEnv* ev, // free block allocated earlier by Alloc()
|
||||
void* inBlock);
|
||||
|
||||
NS_IMETHOD HeapAddStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
NS_IMETHOD HeapCutStrongRef(nsIMdbEnv* ev); // does nothing
|
||||
// } ===== end nsIMdbHeap methods =====
|
||||
|
||||
};
|
||||
|
||||
//3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
|
||||
|
||||
#endif /* _ORKINHEAP_ */
|
Загрузка…
Ссылка в новой задаче