/* (C) Copyright International Business Machines Corporation 23 January */
/* 1990.  All Rights Reserved. */
/*  */
/* See the file USERAGREEMENT distributed with this software for full */
/* terms and conditions of use. */
#ifndef lint
static char sccsinfo[] = "@(#)o_poly.c	1.10 3/13/90";
#endif

#include "ops.h"
#include "recursiv.h"
#include "storage.h"
#include "sysdep.h"
#include "accessors.h"

#define Dst (DstObj->value)
#define Src (SrcObj->value)
#define Src1 (Src1Obj->value)
#define Src2 (Src2Obj->value)

extern datarep dr_polymorph;


/* fix later: use typename and typestate fields, check mismatch, etc... */

NILOP(o_wrap)
{
    void re_finalize();

    dfd_polymorph *poly;
    extern flag cherm_flag;

    if ((poly = new(dfd_polymorph)) is nil)
      raise(Depletion);
    else {
	poly->obj = *SrcObj;	/* "move" source object into the polymorph */

	/* fix later: deal with polymorph_info in qualifier */

	set_bottom(&poly->typename);
	set_bottom(&poly->typestate);

        if (not cherm_flag)
	  re_finalize(DstObj, F_DISCARD, args->sched);
				/* finalize the value of the destination; */

	Dst.polymorph = poly;	/* initialize result */
	set_init(DstObj, dr_polymorph);

	set_bottom(SrcObj);	/* wrap is move-semantic, leaves src uninit */
    }
}


NILOP(o_unwrap)			/* exceptionless */
{
    void re_finalize();

    extern flag cherm_flag;

    OPCHK(SrcObj,polymorph);
    if (not cherm_flag)
      re_finalize(DstObj, F_DISCARD, args->sched);
				/* finalize the value of the destination; */

    *DstObj = Src.polymorph->obj; /* "move" object from polymorph into dst */

    { dispose(Src.polymorph, dfd_polymorph); }
    set_bottom(SrcObj);		/* discard and uninitialize the source */
}

NILOP(o_inspect_poly)
{
    void re_finalize();

    extern datarep *qdatarepmap[];
    extern flag cherm_flag;

    OPCHK(SrcObj,polymorph);
    if (not cherm_flag)
      re_finalize(DstObj, F_DISCARD, args->sched);
				/* finalize the value of the destination; */

				/* make a quopy of the object */ 
    DstObj->value = Src.polymorph->obj.value;
    DstObj->tsdr = qdatarepmap[Src.polymorph->obj.tsdr->number];
}

NILOP(o_endinspect_poly)
{
    set_bottom(DstObj);		/* don't really need to do this, but.... */
}


/*ARGSUSED*/
void
fin_polymorph(poly, f_op, sched)
valcell poly;
finalize_op f_op;
schedblock *sched;
{
    Finalize(&poly.polymorph->obj, f_op, sched);
    Finalize(&poly.polymorph->typename, f_op, sched);
    Finalize(&poly.polymorph->typestate, f_op, sched);
    { dispose(poly.polymorph, dfd_polymorph); }
}

predef_exception
cp_polymorph(dst, src)
valcell *dst, src;
{
    predef_exception re_copy();
    predef_exception retcode;
    valcell newpoly;

    if ((newpoly.polymorph = new(dfd_polymorph)) is nil)
      return(Depletion);
    else {

	set_bottom(&newpoly.polymorph->obj);
	set_bottom(&newpoly.polymorph->typename);
	set_bottom(&newpoly.polymorph->typestate);
	retcode = re_copy(& src.polymorph->obj,
			  & newpoly.polymorph->obj);
	if (retcode isnt Normal)
	  goto cleanup;
	retcode = re_copy(& src.polymorph->typename,
			  & newpoly.polymorph->typename);
	if (retcode isnt Normal)
	  goto cleanup;
	retcode = re_copy(& src.polymorph->typestate,
			  & newpoly.polymorph->typestate);
	if (retcode isnt Normal)
	  goto cleanup;
	dst->polymorph = newpoly.polymorph;
	return(Normal);

      cleanup:
	/* one of the copy operations raised an exception */
	fin_polymorph(newpoly, F_DISCARD, nil);
	return(retcode);
    }
}


status
eq_polymorph(poly1, poly2)
valcell poly1, poly2;
{
    return(Equal(&poly1.polymorph->obj, &poly2.polymorph->obj));
}



comparison
cmp_polymorph(poly1, poly2)
valcell poly1, poly2;
{
    comparison re_comparekeys();

    return(re_comparekeys(& poly1.polymorph->obj, & poly2.polymorph->obj));
}
